diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/char/char.c | 5 | ||||
-rw-r--r-- | src/char/inter.c | 3 | ||||
-rw-r--r-- | src/char/pincode.c | 17 | ||||
-rw-r--r-- | src/common/md5calc.c | 2 | ||||
-rw-r--r-- | src/login/login.c | 4 | ||||
-rw-r--r-- | src/map/atcommand.c | 5 | ||||
-rw-r--r-- | src/map/clan.c | 3 | ||||
-rw-r--r-- | src/map/clif.c | 249 | ||||
-rw-r--r-- | src/map/packets.h | 23 | ||||
-rw-r--r-- | src/map/packets_keys_main.h | 23 | ||||
-rw-r--r-- | src/map/packets_keys_zero.h | 17 | ||||
-rw-r--r-- | src/map/packets_shuffle_main.h | 107 | ||||
-rw-r--r-- | src/map/packets_shuffle_zero.h | 101 | ||||
-rw-r--r-- | src/map/script.c | 1 | ||||
-rw-r--r-- | src/map/script.h | 1 | ||||
-rw-r--r-- | src/map/unit.c | 16 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking.Defs.inc | 2 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc | 4 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc | 1 | ||||
-rw-r--r-- | src/plugins/HPMHooking/HPMHooking_map.Hooks.inc | 27 | ||||
-rw-r--r-- | src/plugins/mapcache.c | 106 |
21 files changed, 629 insertions, 88 deletions
diff --git a/src/char/char.c b/src/char/char.c index aef35f216..0069e7f1d 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3328,7 +3328,12 @@ void char_char_name_ack(int fd, int char_id) WFIFOHEAD(fd,30); WFIFOW(fd,0) = 0x2b09; WFIFOL(fd,2) = char_id; +#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) + if (chr->loadName(char_id, WFIFOP(fd,6)) == 0) + WFIFOL(fd, 6) = 0; +#else chr->loadName(char_id, WFIFOP(fd,6)); +#endif WFIFOSET(fd,30); } diff --git a/src/char/inter.c b/src/char/inter.c index baa000d82..b095a046d 100644 --- a/src/char/inter.c +++ b/src/char/inter.c @@ -527,12 +527,15 @@ void mapif_parse_accinfo2(bool success, int map_fd, int u_fd, int u_aid, int acc inter->msg_to_fd(map_fd, u_fd, u_aid, "-- Account %d --", account_id); inter->msg_to_fd(map_fd, u_fd, u_aid, "User: %s | GM Group: %d | State: %d", userid, group_id, state); +// enable this if you really know what you doing. +#if 0 if (*user_pass != '\0') { /* password is only received if your gm level is greater than the one you're searching for */ if (pin_code && *pin_code != '\0') inter->msg_to_fd(map_fd, u_fd, u_aid, "Password: %s (PIN:%s)", user_pass, pin_code); else inter->msg_to_fd(map_fd, u_fd, u_aid, "Password: %s", user_pass ); } +#endif inter->msg_to_fd(map_fd, u_fd, u_aid, "Account e-mail: %s | Birthdate: %s", email, birthdate); inter->msg_to_fd(map_fd, u_fd, u_aid, "Last IP: %s (%s)", last_ip, geoip->getcountry(sockt->str2ip(last_ip))); diff --git a/src/char/pincode.c b/src/char/pincode.c index fc1a4c037..bca1b4394 100644 --- a/src/char/pincode.c +++ b/src/char/pincode.c @@ -68,6 +68,8 @@ void pincode_check(int fd, struct char_session_data* sd) { char pin[5] = "\0\0\0\0"; nullpo_retv(sd); + if (strlen(sd->pincode) != 4) + return; safestrncpy(pin, RFIFOP(fd, 6), sizeof(pin)); pincode->decrypt(sd->pincode_seed, pin); if( pincode->compare( fd, sd, pin ) ){ @@ -87,7 +89,9 @@ int pincode_compare(int fd, struct char_session_data* sd, char* pin) { } else { pincode->sendstate( fd, sd, PINCODE_WRONG ); if( pincode->maxtry && ++sd->pincode_try >= pincode->maxtry ){ - pincode->error( sd->account_id ); + pincode->error(sd->account_id); + chr->authfail_fd(fd, 0); + chr->disconnect_player(sd->account_id); } return 0; } @@ -97,6 +101,8 @@ void pincode_change(int fd, struct char_session_data* sd) { char oldpin[5] = "\0\0\0\0", newpin[5] = "\0\0\0\0"; nullpo_retv(sd); + if (strlen(sd->pincode) != 4) + return; safestrncpy(oldpin, RFIFOP(fd,6), sizeof(oldpin)); pincode->decrypt(sd->pincode_seed,oldpin); if( !pincode->compare( fd, sd, oldpin ) ) @@ -113,6 +119,8 @@ void pincode_setnew(int fd, struct char_session_data* sd) { char newpin[5] = "\0\0\0\0"; nullpo_retv(sd); + if (strlen(sd->pincode) == 4) + return; safestrncpy(newpin, RFIFOP(fd,6), sizeof(newpin)); pincode->decrypt(sd->pincode_seed,newpin); pincode->update( sd->account_id, newpin ); @@ -172,8 +180,11 @@ void pincode_decrypt(unsigned int userSeed, char* pin) { } } - for( i = 0; i < 4; i++ ){ - pin[i] = tab[pin[i] - '0']; + for (i = 0; i < 4; i++ ) { + if (pin[i] < '0' || pin[i] > '9') + pin[i] = '0'; + else + pin[i] = tab[pin[i] - '0']; } sprintf(pin, "%d%d%d%d", pin[0], pin[1], pin[2], pin[3]); diff --git a/src/common/md5calc.c b/src/common/md5calc.c index d2fc32371..d5ce8b5a8 100644 --- a/src/common/md5calc.c +++ b/src/common/md5calc.c @@ -202,7 +202,7 @@ static void md5_buf2binary(const uint8 *buf, const int buf_size, uint8 *output) //1-3 copy_len = buf_size % 64; //The number of bytes which remained is computed. - strncpy((char *)padding_message, (const char *)pbuf, copy_len); // A message is copied to an extended bit sequence. + memcpy((char *)padding_message, (const char *)pbuf, copy_len); // A message is copied to an extended bit sequence. memset(padding_message+copy_len, 0, 64 - copy_len); //It buries by 0 until it becomes extended bit length. padding_message[copy_len] |= 0x80; //The next of a message is 1. diff --git a/src/login/login.c b/src/login/login.c index 5b281c22d..9fe9de0d3 100644 --- a/src/login/login.c +++ b/src/login/login.c @@ -1985,7 +1985,8 @@ int do_final(void) login->dbs->account_engine->db->destroy(login->dbs->account_engine->db); login->dbs->account_engine->db = NULL; } - accounts = NULL; // destroyed in account_engine + login->accounts = NULL; // destroyed in account_engine + accounts = NULL; login->online_db->destroy(login->online_db, NULL); login->auth_db->destroy(login->auth_db, NULL); @@ -2101,6 +2102,7 @@ int do_init(int argc, char** argv) login->dbs->account_engine->constructor = account->db_sql; login->dbs->account_engine->db = login->dbs->account_engine->constructor(); accounts = login->dbs->account_engine->db; + login->accounts = accounts; if( accounts == NULL ) { ShowFatalError("do_init: account engine 'sql' not found.\n"); exit(EXIT_FAILURE); diff --git a/src/map/atcommand.c b/src/map/atcommand.c index 2bcb22738..b0ad24c11 100644 --- a/src/map/atcommand.c +++ b/src/map/atcommand.c @@ -10056,6 +10056,7 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa { char params[100], command[100]; char output[CHAT_SIZE_MAX]; + bool logCommand; // Reconstructed message char atcmd_msg[CHAT_SIZE_MAX]; @@ -10199,6 +10200,7 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa } } + logCommand = info->log; //Attempt to use the command if ((info->func(fd, ssd, command, params,info) != true)) { #ifdef AUTOTRADE_PERSISTENCY @@ -10210,7 +10212,8 @@ bool atcommand_exec(const int fd, struct map_session_data *sd, const char *messa return true; } - if (info->log) /* log only if this command should be logged [Ind/Hercules] */ + // info->log cant be used here, because info can be freed [4144] + if (logCommand) /* log only if this command should be logged [Ind/Hercules] */ logs->atcommand(sd, is_atcommand ? atcmd_msg : message); return true; diff --git a/src/map/clan.c b/src/map/clan.c index 865f5a4cd..7aa9be5d4 100644 --- a/src/map/clan.c +++ b/src/map/clan.c @@ -997,10 +997,11 @@ void clan_reload(void) */ void do_init_clan(bool minimal) { + clan->db = idb_alloc(DB_OPT_RELEASE_DATA); + if (minimal) { return; } - clan->db = idb_alloc(DB_OPT_RELEASE_DATA); clan->config_read(false); timer->add_func_list(clan->inactivity_kick, "clan_inactivity_kick"); } diff --git a/src/map/clif.c b/src/map/clif.c index 4d883eacb..546247c3c 100644 --- a/src/map/clif.c +++ b/src/map/clif.c @@ -6088,14 +6088,29 @@ void clif_wis_end(int fd, int flag) { /// Returns character name requested by char_id (ZC_ACK_REQNAME_BYGID). /// 0194 <char id>.L <name>.24B +/// 0af7 <flag>.W <char id>.L <name>.24B void clif_solved_charname(int fd, int charid, const char* name) { nullpo_retv(name); - WFIFOHEAD(fd,packet_len(0x194)); - WFIFOW(fd,0)=0x194; - WFIFOL(fd,2)=charid; - safestrncpy(WFIFOP(fd,6), name, NAME_LENGTH); - WFIFOSET(fd,packet_len(0x194)); +#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) + WFIFOHEAD(fd, packet_len(0x0af7)); + WFIFOW(fd, 0) = 0xaf7; + if (*name == 0) { + WFIFOW(fd, 2) = 2; + memset(WFIFOP(fd, 8), 0, NAME_LENGTH); + } else { + WFIFOW(fd, 2) = 3; + safestrncpy(WFIFOP(fd, 8), name, NAME_LENGTH); + } + WFIFOL(fd, 4) = charid; + WFIFOSET(fd, packet_len(0x0af7)); +#else + WFIFOHEAD(fd, packet_len(0x194)); + WFIFOW(fd, 0) = 0x194; + WFIFOL(fd, 2) = charid; + safestrncpy(WFIFOP(fd, 6), name, NAME_LENGTH); + WFIFOSET(fd, packet_len(0x194)); +#endif } /// Presents a list of items that can be carded/composed (ZC_ITEMCOMPOSITION_LIST). @@ -10999,13 +11014,21 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) __attribute_ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) { int len = RFIFOW(fd,2)-15; - int limit = RFIFOW(fd,4); - bool pub = (RFIFOB(fd,6) != 0); - const char *password = RFIFOP(fd,7); //not zero-terminated - const char *title = RFIFOP(fd,15); // not zero-terminated + int limit; + bool pub; + const char *password; //not zero-terminated + const char *title; // not zero-terminated char s_password[CHATROOM_PASS_SIZE]; char s_title[CHATROOM_TITLE_SIZE]; + if (len < 1) + return; + + limit = RFIFOW(fd, 4); + pub = (RFIFOB(fd, 6) != 0); + password = RFIFOP(fd, 7); //not zero-terminated + title = RFIFOP(fd, 15); // not zero-terminated + if (pc_ismuted(&sd->sc, MANNER_NOROOM)) return; if(battle_config.basic_skill_check && !pc->check_basicskill(sd, 4)) { @@ -11021,9 +11044,6 @@ void clif_parse_CreateChatRoom(int fd, struct map_session_data* sd) return; } - if( len <= 0 ) - return; // invalid input - safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte @@ -11050,15 +11070,20 @@ void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) __attr void clif_parse_ChatRoomStatusChange(int fd, struct map_session_data* sd) { int len = RFIFOW(fd,2)-15; - int limit = RFIFOW(fd,4); - bool pub = (RFIFOB(fd,6) != 0); - const char *password = RFIFOP(fd,7); // not zero-terminated - const char *title = RFIFOP(fd,15); // not zero-terminated + int limit; + bool pub; + const char *password; // not zero-terminated + const char *title; // not zero-terminated char s_password[CHATROOM_PASS_SIZE]; char s_title[CHATROOM_TITLE_SIZE]; - if( len <= 0 ) - return; // invalid input + if (len < 1) + return; + + limit = RFIFOW(fd, 4); + pub = (RFIFOB(fd, 6) != 0); + password = RFIFOP(fd, 7); // not zero-terminated + title = RFIFOP(fd, 15); // not zero-terminated safestrncpy(s_password, password, CHATROOM_PASS_SIZE); safestrncpy(s_title, title, min(len+1,CHATROOM_TITLE_SIZE)); //NOTE: assumes that safestrncpy will not access the len+1'th byte @@ -11074,7 +11099,7 @@ void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) __attribute /// 1 = normal void clif_parse_ChangeChatOwner(int fd, struct map_session_data* sd) { - chat->change_owner(sd, RFIFOP(fd,6)); + chat->change_owner(sd, RFIFOP(fd,6)); // non null terminated } void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__((nonnull (2))); @@ -11082,7 +11107,7 @@ void clif_parse_KickFromChat(int fd,struct map_session_data *sd) __attribute__(( /// 00e2 <name>.24B void clif_parse_KickFromChat(int fd,struct map_session_data *sd) { - chat->kick(sd, RFIFOP(fd,2)); + chat->kick(sd, RFIFOP(fd,2)); // non null terminated } void clif_parse_ChatLeave(int fd, struct map_session_data* sd) __attribute__((nonnull (2))); @@ -11841,17 +11866,21 @@ void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) __attribute_ /// 01d5 <packet len>.W <npc id>.L <string>.?B void clif_parse_NpcStringInput(int fd, struct map_session_data* sd) { + int len = RFIFOW(fd, 2); // [4144] can't confirm exact client version. At least >= correct for 20150513 #if PACKETVER >= 20151029 - int message_len = RFIFOW(fd, 2) - 7; + int message_len = len - 7; #else - int message_len = RFIFOW(fd, 2) - 8; + int message_len = len - 8; #endif - int npcid = RFIFOL(fd,4); - const char *message = RFIFOP(fd,8); + int npcid; + const char *message; - if( message_len <= 0 ) - return; // invalid input + if (len < 9) + return; + + npcid = RFIFOL(fd, 4); + message = RFIFOP(fd, 8); safestrncpy(sd->npc_str, message, min(message_len,CHATBOX_SIZE)); npc->scriptcont(sd, npcid, false); @@ -13005,9 +13034,15 @@ void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) __attribute__(( /// 0134 <packet len>.W <account id>.L { <amount>.W <index>.W }* void clif_parse_PurchaseReq(int fd, struct map_session_data* sd) { - int len = (int)RFIFOW(fd,2) - 8; - int id = RFIFOL(fd,4); - const uint8 *data = RFIFOP(fd,8); + int len = (int)RFIFOW(fd, 2) - 8; + int id; + const uint8 *data; + + if (len < 1) + return; + + id = RFIFOL(fd, 4); + data = RFIFOP(fd, 8); vending->purchase(sd, id, sd->vended_id, data, len/4); @@ -13020,10 +13055,16 @@ void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) __attribute__( /// 0801 <packet len>.W <account id>.L <unique id>.L { <amount>.W <index>.W }* void clif_parse_PurchaseReq2(int fd, struct map_session_data* sd) { - int len = (int)RFIFOW(fd,2) - 12; - int aid = RFIFOL(fd,4); - int uid = RFIFOL(fd,8); - const uint8 *data = RFIFOP(fd,12); + int len = (int)RFIFOW(fd, 2) - 12; + int aid; + int uid; + const uint8 *data; + + if (len < 1) + return; + aid = RFIFOL(fd, 4); + uid = RFIFOL(fd, 8); + data = RFIFOP(fd, 12); vending->purchase(sd, aid, uid, data, len/4); @@ -13040,9 +13081,16 @@ void clif_parse_OpenVending(int fd, struct map_session_data* sd) __attribute__(( /// 1 = open void clif_parse_OpenVending(int fd, struct map_session_data* sd) { short len = (short)RFIFOW(fd,2) - 85; - const char *message = RFIFOP(fd,4); - bool flag = (RFIFOB(fd,84) != 0) ? true : false; - const uint8 *data = RFIFOP(fd,85); + const char *message; + bool flag; + const uint8 *data; + + if (len < 1) + return; + + message = RFIFOP(fd,4); + flag = (RFIFOB(fd,84) != 0) ? true : false; + data = RFIFOP(fd,85); if( !flag ) sd->state.prevend = sd->state.workinprogress = 0; @@ -13135,12 +13183,14 @@ void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) __a void clif_parse_GuildChangePositionInfo(int fd, struct map_session_data *sd) { int i; + int count = (RFIFOW(fd, 2) - 4) / 40; - if(!sd->state.gmaster_flag) + if (!sd->state.gmaster_flag) return; - for(i = 4; i < RFIFOW(fd,2); i += 40 ){ - guild->change_position(sd->status.guild_id, RFIFOL(fd,i), RFIFOL(fd,i+4), RFIFOL(fd,i+12), RFIFOP(fd,i+16)); + for (i = 0; i < count; i ++ ) { + int idx = i * 40 + 4; + guild->change_position(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), RFIFOL(fd, idx + 12), RFIFOP(fd, idx + 16)); } } @@ -13151,6 +13201,7 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) { int i; int len = RFIFOW(fd, 2); + int count = (len - 4) / 12; if(!sd->state.gmaster_flag) return; @@ -13161,10 +13212,11 @@ void clif_parse_GuildChangeMemberPosition(int fd, struct map_session_data *sd) return; } - for(i=4;i<RFIFOW(fd,2);i+=12){ - int position = RFIFOL(fd, i + 8); - if (position > 0) { - guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, i), RFIFOL(fd, i + 4), position); + for (i = 0; i < count; i++) { + int idx = i * 12 + 4; + int position = RFIFOL(fd, idx + 8); + if (position > 0 && position < MAX_GUILDPOSITION) { + guild->change_memberposition(sd->status.guild_id, RFIFOL(fd, idx), RFIFOL(fd, idx + 4), position); } } } @@ -13548,12 +13600,15 @@ void clif_parse_GuildBreak(int fd, struct map_session_data *sd) __attribute__((n /// key: /// now guild name; might have been (intended) email, since the /// field name and size is same as the one in CH_DELETE_CHAR. -void clif_parse_GuildBreak(int fd, struct map_session_data *sd) { +void clif_parse_GuildBreak(int fd, struct map_session_data *sd) +{ + char key[40]; if( map->list[sd->bl.m].flag.guildlock ) { clif->message(fd, msg_fd(fd,228)); // Guild modification is disabled in this map. return; } - guild->dobreak(sd, RFIFOP(fd,2)); + safestrncpy(key, RFIFOP(fd, 2), 40); + guild->dobreak(sd, key); } /// Pet @@ -14142,6 +14197,7 @@ void clif_parse_NoviceExplosionSpirits(int fd, struct map_session_data *sd) /// Toggles a single friend online/offline [Skotlex] (ZC_FRIENDS_STATE). /// 0206 <account id>.L <char id>.L <state>.B +/// 0206 <account id>.L <char id>.L <state>.B <name>.24B /// state: /// 0 = online /// 1 = offline @@ -14161,7 +14217,13 @@ void clif_friendslist_toggle(struct map_session_data *sd,int account_id, int cha WFIFOW(fd, 0) = 0x206; WFIFOL(fd, 2) = sd->status.friends[i].account_id; WFIFOL(fd, 6) = sd->status.friends[i].char_id; - WFIFOB(fd,10) = !online; //Yeah, a 1 here means "logged off", go figure... + WFIFOB(fd, 10) = !online; //Yeah, a 1 here means "logged off", go figure... +#ifndef PACKETVER_ZERO +#if PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221) + memcpy(WFIFOP(fd, 11), sd->status.friends[i].name, NAME_LENGTH); +#endif +#endif // PACKETVER_ZERO + WFIFOSET(fd, packet_len(0x206)); } @@ -14178,22 +14240,30 @@ int clif_friendslist_toggle_sub(struct map_session_data *sd,va_list ap) /// Sends the whole friends list (ZC_FRIENDS_LIST). /// 0201 <packet len>.W { <account id>.L <char id>.L <name>.24B }* +/// 0201 <packet len>.W { <account id>.L <char id>.L }* void clif_friendslist_send(struct map_session_data *sd) { int i = 0, n, fd = sd->fd; +#if !defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221)) + const int offset = 8; +#else + const int offset = 32; +#endif nullpo_retv(sd); // Send friends list - WFIFOHEAD(fd, MAX_FRIENDS * 32 + 4); + WFIFOHEAD(fd, MAX_FRIENDS * offset + 4); WFIFOW(fd, 0) = 0x201; for(i = 0; i < MAX_FRIENDS && sd->status.friends[i].char_id; i++) { - WFIFOL(fd, 4 + 32 * i + 0) = sd->status.friends[i].account_id; - WFIFOL(fd, 4 + 32 * i + 4) = sd->status.friends[i].char_id; - memcpy(WFIFOP(fd, 4 + 32 * i + 8), &sd->status.friends[i].name, NAME_LENGTH); + WFIFOL(fd, 4 + offset * i + 0) = sd->status.friends[i].account_id; + WFIFOL(fd, 4 + offset * i + 4) = sd->status.friends[i].char_id; +#if !(!defined(PACKETVER_ZERO) && (PACKETVER >= 20180307 || (defined(PACKETVER_RE) && PACKETVER >= 20180221))) + memcpy(WFIFOP(fd, 4 + offset * i + 8), &sd->status.friends[i].name, NAME_LENGTH); +#endif } if (i) { - WFIFOW(fd,2) = 4 + 32 * i; + WFIFOW(fd,2) = 4 + offset * i; WFIFOSET(fd, WFIFOW(fd,2)); } @@ -15302,17 +15372,19 @@ void clif_parse_Mail_winopen(int fd, struct map_session_data *sd) void clif_parse_Mail_send(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); /// Request to send mail (CZ_MAIL_SEND). /// 0248 <packet len>.W <recipient>.24B <title>.40B <body len>.B <body>.?B + void clif_parse_Mail_send(int fd, struct map_session_data *sd) { struct mail_message msg; int body_len; + int len = RFIFOW(fd, 2); if( !chrif->isconnected() ) return; if( sd->state.trading ) return; - if( RFIFOW(fd,2) < 69 ) { + if (len < 69) { ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id); return; } @@ -15328,6 +15400,11 @@ void clif_parse_Mail_send(int fd, struct map_session_data *sd) if (body_len > MAIL_BODY_LENGTH) body_len = MAIL_BODY_LENGTH; + if (body_len + 69 > len) { + ShowWarning("Invalid Msg Len from account %d.\n", sd->status.account_id); + return; + } + memset(&msg, 0, sizeof(msg)); if (!mail->setattachment(sd, &msg)) { // Invalid Append condition clif->mail_send(sd->fd, true); // fail @@ -15833,15 +15910,24 @@ void clif_parse_cashshop_buy(int fd, struct map_session_data *sd) fail = npc->cashshop_buy(sd, nameid, amount, points); #else int len = RFIFOW(fd,2); - int points = RFIFOL(fd,4); - int count = RFIFOW(fd,8); + int points; + int count; struct itemlist item_list = { 0 }; int i; - if( len < 10 || len != 10 + count * 4) { + if (len < 10) { + ShowWarning("Player %d sent incorrect cash shop buy packet (len %d)!\n", sd->status.char_id, len); + return; + } + + points = RFIFOL(fd, 4); + count = RFIFOW(fd, 8); + + if (len != 10 + count * 4) { ShowWarning("Player %d sent incorrect cash shop buy packet (len %d:%d)!\n", sd->status.char_id, len, 10 + count * 4); return; } + VECTOR_INIT(item_list); VECTOR_ENSURE(item_list, count, 1); for (i = 0; i < count; i++) { @@ -16879,7 +16965,7 @@ void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd) __at /// S 07e4 <length>.w <option>.l <val>.l {<index>.w <amount>.w).4b* void clif_parse_ItemListWindowSelected(int fd, struct map_session_data *sd) { - int n = ((int)RFIFOW(fd,2) - 12) / 4; + int n = ((int)RFIFOW(fd, 2) - 12) / 4; int type = RFIFOL(fd,4); int flag = RFIFOL(fd,8); // Button clicked: 0 = Cancel, 1 = OK struct itemlist item_list = { 0 }; @@ -17010,7 +17096,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { char storename[MESSAGE_SIZE]; unsigned char result; int zenylimit; - unsigned int count, packet_len; + int count, packet_len; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); @@ -17018,7 +17104,7 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { // TODO: Make this check global for all variable length packets. if( packet_len < 89 ) {// minimum packet length - ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 89U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqOpenBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 89U, packet_len, sd->bl.id); return; } @@ -17030,9 +17116,12 @@ void clif_parse_ReqOpenBuyingStore(int fd, struct map_session_data* sd) { // so that buyingstore_create knows, how many elements it has access to packet_len-= info->pos[4]; + if (packet_len < 0) + return; + if( packet_len%blocksize ) { - ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); + ShowError("clif_parse_ReqOpenBuyingStore: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } count = packet_len/blocksize; @@ -17201,14 +17290,15 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) { const unsigned int blocksize = 6; const uint8 *itemlist; int account_id; - unsigned int count, packet_len, buyer_id; + unsigned int buyer_id; + int count, packet_len; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); if( packet_len < 12 ) {// minimum packet length - ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 12U, packet_len, sd->bl.id); + ShowError("clif_parse_ReqTradeBuyingStore: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 12U, packet_len, sd->bl.id); return; } @@ -17218,10 +17308,12 @@ void clif_parse_ReqTradeBuyingStore(int fd, struct map_session_data* sd) { // so that buyingstore_trade knows, how many elements it has access to packet_len-= info->pos[3]; + if (packet_len < 0) + return; if( packet_len%blocksize ) { - ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %u (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize); + ShowError("clif_parse_ReqTradeBuyingStore: Unexpected item list size %d (account_id=%d, buyer_id=%d, block size=%u)\n", packet_len, sd->bl.id, account_id, blocksize); return; } count = packet_len/blocksize; @@ -17340,14 +17432,15 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) { const uint8* itemlist; const uint8* cardlist; unsigned char type; - unsigned int min_price, max_price, packet_len, count, item_count, card_count; + unsigned int min_price, max_price; + int packet_len, count, item_count, card_count; struct s_packet_db* info = &packet_db[RFIFOW(fd,0)]; packet_len = RFIFOW(fd,info->pos[0]); if( packet_len < 15 ) {// minimum packet length - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%u, account_id=%d).\n", 15U, packet_len, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected length=%u, length=%d, account_id=%d).\n", 15U, packet_len, sd->bl.id); return; } @@ -17357,24 +17450,28 @@ void clif_parse_SearchStoreInfo(int fd, struct map_session_data* sd) { item_count = RFIFOB(fd,info->pos[4]); card_count = RFIFOB(fd,info->pos[5]); itemlist = RFIFOP(fd,info->pos[6]); - cardlist = RFIFOP(fd,info->pos[6]+blocksize*item_count); // check, if there is enough data for the claimed count of items packet_len-= info->pos[6]; + if (packet_len < 0) + return; + if( packet_len%blocksize ) { - ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %u (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); + ShowError("clif_parse_SearchStoreInfo: Unexpected item list size %d (account_id=%d, block size=%u)\n", packet_len, sd->bl.id, blocksize); return; } count = packet_len/blocksize; if( count < item_count+card_count ) { - ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%u, count=%u, account_id=%d).\n", item_count+card_count, count, sd->bl.id); + ShowError("clif_parse_SearchStoreInfo: Malformed packet (expected count=%d, count=%d, account_id=%d).\n", item_count+card_count, count, sd->bl.id); return; } + cardlist = RFIFOP(fd, info->pos[6] + blocksize * item_count); + searchstore->query(sd, type, min_price, max_price, (const unsigned short*)itemlist, item_count, (const unsigned short*)cardlist, card_count); } @@ -17994,16 +18091,30 @@ void clif_parse_CashShopSchedule(int fd, struct map_session_data *sd) #endif } +/// R 0848 <len>.W <limit>.W <kafra pay>.L (<item id>.L <amount>.L <tab>.W)* void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) __attribute__((nonnull (2))); void clif_parse_CashShopBuy(int fd, struct map_session_data *sd) { - unsigned short limit = RFIFOW(fd, 4), i, j; - unsigned int kafra_pay = RFIFOL(fd, 6);// [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing) + int len = RFIFOW(fd, 2); + unsigned short limit, i, j; + unsigned int kafra_pay; + int count; if (map->list[sd->bl.m].flag.nocashshop) { clif->messagecolor_self(fd, COLOR_RED, msg_fd(fd,1489)); //Cash Shop is disabled in this map return; } + if (len < 10) + return; + + limit = RFIFOW(fd, 4); + kafra_pay = RFIFOL(fd, 6); // [Ryuuzaki] - These are free cash points (strangely #CASH = main cash currently for us, confusing) + count = (len - 10) / 10; + if (count != limit) { + ShowError("Wrong cash shop limit: %d\n", limit); + return; + } + for(i = 0; i < limit; i++) { int qty = RFIFOL(fd, 14 + ( i * 10 )); int id = RFIFOL(fd, 10 + ( i * 10 )); diff --git a/src/map/packets.h b/src/map/packets.h index 4c41a7e8f..462efd31b 100644 --- a/src/map/packets.h +++ b/src/map/packets.h @@ -3995,11 +3995,15 @@ packet(0x96e,-1,clif->ackmergeitems); packet(0x0af3,-1,clif->pDull/*,XXX*/); packet(0x0af4,11,clif->pDull/*,XXX*/); // changed packet sizes - packet(0x0821,102); // AC_OTP_USER packet(0x0ae6,10,clif->pDull/*,XXX*/); #endif #endif // PACKETVER_ZERO +#if PACKETVER >= 20180131 +// changed packet sizes + packet(0x0821,102); // AC_OTP_USER +#endif + #ifdef PACKETVER_ZERO // 2018-02-07bRagexe_zero #if PACKETVER >= 20180207 @@ -4022,5 +4026,22 @@ packet(0x96e,-1,clif->ackmergeitems); #endif #endif // PACKETVER_ZERO +#ifdef PACKETVER_RE +// 2018-02-21aRagexeRE +#if PACKETVER >= 20180221 +// new packets +// changed packet sizes + packet(0x0206,35); // ZC_FRIENDS_STATE +#endif +#endif // PACKETVER_RE + +#ifndef PACKETVER_ZERO +// 2018-03-07bRagexe +#if PACKETVER >= 20180307 +// new packets +// changed packet sizes + packet(0x0206,35); // ZC_FRIENDS_STATE +#endif +#endif // PACKETVER_ZERO #endif /* MAP_PACKETS_H */ diff --git a/src/map/packets_keys_main.h b/src/map/packets_keys_main.h index 9aa39fad5..066e7d2c3 100644 --- a/src/map/packets_keys_main.h +++ b/src/map/packets_keys_main.h @@ -1949,15 +1949,32 @@ packetKeys(0x21F477F4,0x37F437F4,0x37F437F4); #endif -// 2018-01-24bRagexe, 2018-01-24bRagexeRE -#if PACKETVER == 20180124 +// 2018-01-24bRagexe, 2018-01-24bRagexeRE, 2018-01-31Ragexe +#if PACKETVER == 20180124 || \ + PACKETVER == 20180131 packetKeys(0x7EAA1CE0,0x415D1CFD,0x4C8F19FA); #endif -// 2018-02-07bRagexe, 2018-02-07bRagexeRE +// 2018-02-07bRagexe, 2018-02-07bRagexeRE, 2018-02-07cRagexe #if PACKETVER == 20180207 packetKeys(0x45AA1B44,0x20E716B7,0x5388105C); #endif +// 2018-02-13aRagexe, 2018-02-13aRagexeRE, 2018-02-13bRagexe +#if PACKETVER == 20180213 + packetKeys(0x189D69B2,0x43B85EAD,0x2B7A687E); +#endif + +// 2018-02-21aRagexeRE, 2018-02-21bRagexe, 2018-02-21bRagexeRE +#if PACKETVER == 20180221 + packetKeys(0x6E2F6233,0x193B0A66,0x0D1D2CA5); +#endif + +// 2018-03-07bRagexe, 2018-03-07bRagexeRE, 2018-03-09aRagexe +#if PACKETVER == 20180307 || \ + PACKETVER == 20180309 + packetKeys(0x47DA10EB,0x4B922CCF,0x765C5055); +#endif + #endif /* MAP_PACKETS_MAIN_KEYS_H */ diff --git a/src/map/packets_keys_zero.h b/src/map/packets_keys_zero.h index 101d0b973..75196e6b4 100644 --- a/src/map/packets_keys_zero.h +++ b/src/map/packets_keys_zero.h @@ -124,5 +124,22 @@ packetKeys(0x07CB29CB,0x69CB69CB,0x69CB69CB); #endif +// 2018-02-13aRagexe_zero +#if PACKETVER == 20180213 + packetKeys(0x0513075E,0x347075AF,0x67C56C6F); +#endif + +// 2018-02-21aRagexe_zero +#if PACKETVER == 20180221 + packetKeys(0x28ED7635,0x76591F21,0x59383498); +#endif + +// 2018-02-28bRagexe_zero, 2018-03-07aRagexe_zero, 2018-03-09aRagexe_zero +#if PACKETVER == 20180228 || \ + PACKETVER == 20180307 || \ + PACKETVER == 20180309 + packetKeys(0x56C82ABE,0x61AE2B2E,0x472E272E); +#endif + #endif /* MAP_PACKETS_ZERO_KEYS_H */ diff --git a/src/map/packets_shuffle_main.h b/src/map/packets_shuffle_main.h index 13861dd46..aabf9c3f3 100644 --- a/src/map/packets_shuffle_main.h +++ b/src/map/packets_shuffle_main.h @@ -9500,8 +9500,9 @@ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME #endif -// 2018-01-24bRagexe, 2018-01-24bRagexeRE -#if PACKETVER == 20180124 +// 2018-01-24bRagexe, 2018-01-24bRagexeRE, 2018-01-31Ragexe +#if PACKETVER == 20180124 || \ + PACKETVER == 20180131 packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX @@ -9533,7 +9534,7 @@ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME #endif -// 2018-02-07bRagexe, 2018-02-07bRagexeRE +// 2018-02-07bRagexe, 2018-02-07bRagexeRE, 2018-02-07cRagexe #if PACKETVER == 20180207 packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES packet(0x035f,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE @@ -9566,5 +9567,105 @@ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME #endif +// 2018-02-13aRagexe, 2018-02-13aRagexeRE, 2018-02-13bRagexe +#if PACKETVER == 20180213 + packet(0x0369,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD + packet(0x0802,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0817,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x085a,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x086f,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x0874,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0875,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0878,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x087b,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x0882,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x088c,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x0892,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x0898,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x089c,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x08a3,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x08a5,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x08a9,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x08ad,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0917,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x0922,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x0924,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x0926,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0933,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT + packet(0x0936,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x093c,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0943,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0955,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x095a,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x0962,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER +#endif + +// 2018-02-21aRagexeRE, 2018-02-21bRagexe, 2018-02-21bRagexeRE +#if PACKETVER == 20180221 + packet(0x0202,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0366,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0436,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x0838,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x0867,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x086c,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x086f,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0871,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0876,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER + packet(0x0879,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x087d,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x0880,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x0881,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0883,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x088f,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0891,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x0897,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x0899,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x089d,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0917,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD + packet(0x091e,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0929,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x093d,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x094b,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x094d,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x094e,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x0957,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0964,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x096a,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT +#endif + +// 2018-03-07bRagexe, 2018-03-07bRagexeRE, 2018-03-09aRagexe +#if PACKETVER == 20180307 || \ + PACKETVER == 20180309 + packet(0x0281,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x035f,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0437,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x07e4,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x0861,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0862,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x0864,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x086c,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0870,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x0872,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0877,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x088d,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0893,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x089b,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x08a6,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x08aa,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x08ab,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x0917,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x0920,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x0937,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x0939,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD + packet(0x093d,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x0941,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0944,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER + packet(0x0948,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x0951,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0954,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x0957,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0969,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT +#endif + #endif /* MAP_PACKETS_SHUFFLE_MAIN_H */ diff --git a/src/map/packets_shuffle_zero.h b/src/map/packets_shuffle_zero.h index 38c34b18e..463ab1679 100644 --- a/src/map/packets_shuffle_zero.h +++ b/src/map/packets_shuffle_zero.h @@ -551,5 +551,106 @@ packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME #endif +// 2018-02-13aRagexe_zero +#if PACKETVER == 20180213 + packet(0x022d,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x02c4,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x035f,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0361,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0802,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0815,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x0838,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x085a,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x085d,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER + packet(0x0868,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x087b,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0882,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x0887,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x0888,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x088a,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x088e,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x0899,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x0917,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT + packet(0x091d,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x0922,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0930,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0941,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x0942,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0947,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x094d,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x0958,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x095b,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x095c,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x0967,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD +#endif + +// 2018-02-21aRagexe_zero +#if PACKETVER == 20180221 + packet(0x02c4,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0362,6,clif->pGetCharNameRequest,2); // CZ_REQNAME + packet(0x0364,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x0438,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x0817,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x085b,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x086a,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0878,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x0880,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x0884,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x088d,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0892,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0895,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x08a1,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x08a3,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x091b,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0921,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0923,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER + packet(0x092d,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x0932,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x093b,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x093d,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x093e,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0942,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD + packet(0x0951,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0952,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x0958,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT + packet(0x0959,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x095d,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP +#endif + +// 2018-02-28bRagexe_zero, 2018-03-07aRagexe_zero, 2018-03-09aRagexe_zero +#if PACKETVER == 20180228 || \ + PACKETVER == 20180307 || \ + PACKETVER == 20180309 + packet(0x0202,5,clif->pChangeDir,2,4); // CZ_CHANGE_DIRECTION + packet(0x022d,19,clif->pWantToConnection,2,6,10,14,18); // CZ_ENTER + packet(0x023b,26,clif->pFriendsListAdd,2); // CZ_ADD_FRIENDS + packet(0x0281,-1,clif->pItemListWindowSelected,2,4,8); // CZ_ITEMLISTWIN_RES + packet(0x035f,6,clif->pTickSend,2); // CZ_REQUEST_TIME + packet(0x0360,6,clif->pReqClickBuyingStore,2); // CZ_REQ_CLICK_TO_BUYING_STORE + packet(0x0361,5,clif->pHomMenu,2,4); // CZ_COMMAND_MER + packet(0x0362,6,clif->pDropItem,2,4); // CZ_ITEM_THROW + packet(0x0363,8,clif->pDull/*,XXX*/); // CZ_JOIN_BATTLE_FIELD + packet(0x0364,8,clif->pMoveFromKafra,2,4); // CZ_MOVE_ITEM_FROM_STORE_TO_BODY + packet(0x0365,18,clif->pPartyBookingRegisterReq,2,4); // CZ_PARTY_BOOKING_REQ_REGISTER + packet(0x0366,90,clif->pUseSkillToPosMoreInfo,2,4,6,8,10); // CZ_USE_SKILL_TOGROUND_WITHTALKBOX + packet(0x0368,6,clif->pSolveCharName,2); // CZ_REQNAME_BYGID + packet(0x0369,7,clif->pActionRequest,2,6); // CZ_REQUEST_ACT + packet(0x0436,4,clif->pDull/*,XXX*/); // CZ_GANGSI_RANK + packet(0x0437,5,clif->pWalkToXY,2); // CZ_REQUEST_MOVE + packet(0x0438,10,clif->pUseSkillToPos,2,4,6,8); // CZ_USE_SKILL_TOGROUND + packet(0x07e4,6,clif->pTakeItem,2); // CZ_ITEM_PICKUP + packet(0x07ec,8,clif->pMoveToKafra,2,4); // CZ_MOVE_ITEM_FROM_BODY_TO_STORE + packet(0x0802,26,clif->pPartyInvite2,2); // CZ_PARTY_JOIN_REQ + packet(0x0811,-1,clif->pReqTradeBuyingStore,2,4,8,12); // CZ_REQ_TRADE_BUYING_STORE + packet(0x0815,-1,clif->pReqOpenBuyingStore,2,4,8,9,89); // CZ_REQ_OPEN_BUYING_STORE + packet(0x0817,2,clif->pReqCloseBuyingStore,0); // CZ_REQ_CLOSE_BUYING_STORE + packet(0x0819,-1,clif->pSearchStoreInfo,2,4,5,9,13,14,15); // CZ_SEARCH_STORE_INFO + packet(0x0835,2,clif->pSearchStoreInfoNextPage,0); // CZ_SEARCH_STORE_INFO_NEXT_PAGE + packet(0x0838,12,clif->pSearchStoreInfoListItemClick,2,6,10); // CZ_SSILIST_ITEM_CLICK + packet(0x083c,10,clif->pUseSkillToId,2,4,6); // CZ_USE_SKILL + packet(0x0930,36,clif->pStoragePassword,0); // CZ_ACK_STORE_PASSWORD + packet(0x096a,6,clif->pGetCharNameRequest,2); // CZ_REQNAME +#endif + #endif /* MAP_PACKETS_SHUFFLE_ZERO_H */ diff --git a/src/map/script.c b/src/map/script.c index 26de803d7..d653800cc 100644 --- a/src/map/script.c +++ b/src/map/script.c @@ -25180,6 +25180,7 @@ void script_defaults(void) script->search_str = script_search_str; script->setd_sub = setd_sub; script->attach_state = script_attach_state; + script->sprintf = script_sprintf; script->queue = script_hqueue_get; script->queue_add = script_hqueue_add; diff --git a/src/map/script.h b/src/map/script.h index 14d20838d..2dc3b2327 100644 --- a/src/map/script.h +++ b/src/map/script.h @@ -909,6 +909,7 @@ struct script_interface { int (*buildin_mobuseskill_sub) (struct block_list *bl, va_list ap); int (*cleanfloor_sub) (struct block_list *bl, va_list ap); int (*run_func) (struct script_state *st); + bool (*sprintf) (struct script_state *st, int start, struct StringBuf *out); const char *(*getfuncname) (struct script_state *st); // for ENABLE_CASE_CHECK unsigned int (*calc_hash_ci) (const char *p); diff --git a/src/map/unit.c b/src/map/unit.c index 938b587f3..c40aa7000 100644 --- a/src/map/unit.c +++ b/src/map/unit.c @@ -2210,6 +2210,7 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) //Non-players use the sync packet on the walk timer. [Skotlex] if (tid == INVALID_TIMER && sd) clif->fixpos(src); + map->freeblock_lock(); if( DIFF_TICK(ud->attackabletime,tick) <= 0 ) { if (battle_config.attack_direction_change && (src->type&battle_config.attack_direction_change)) { ud->dir = map->calc_dir(src, target->x,target->y ); @@ -2219,8 +2220,10 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) if(md) { //First attack is always a normal attack if(md->state.skillstate == MSS_ANGRY || md->state.skillstate == MSS_BERSERK) { - if (mob->skill_use(md,tick,-1)) + if (mob->skill_use(md,tick,-1)) { + map->freeblock_unlock(); return 1; + } } else { // Set mob's ANGRY/BERSERK states. md->state.skillstate = md->state.aggressive?MSS_ANGRY:MSS_BERSERK; @@ -2232,21 +2235,23 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) map->foreachinrange(mob->linksearch, src, md->db->range2, BL_MOB, md->class_, target, tick); } } - if (src->type == BL_PET && pet->attackskill(BL_UCAST(BL_PET, src), target->id)) + if (src->type == BL_PET && pet->attackskill(BL_UCAST(BL_PET, src), target->id)) { + map->freeblock_unlock(); return 1; + } - map->freeblock_lock(); ud->attacktarget_lv = battle->weapon_attack(src,target,tick,0); if(sd && sd->status.pet_id > 0 && sd->pd && battle_config.pet_attack_support) pet->target_check(sd,target,0); - map->freeblock_unlock(); /** * Applied when you're unable to attack (e.g. out of ammo) * We should stop here otherwise timer keeps on and this happens endlessly **/ - if( ud->attacktarget_lv == ATK_NONE ) + if (ud->attacktarget_lv == ATK_NONE) { + map->freeblock_unlock(); return 1; + } ud->attackabletime = tick + sstatus->adelay; // You can't move if you can't attack neither. @@ -2260,6 +2265,7 @@ int unit_attack_timer_sub(struct block_list* src, int tid, int64 tick) pc->update_idle_time(sd, BCIDLE_ATTACK); ud->attacktimer = timer->add(ud->attackabletime,unit->attack_timer,src->id,0); } + map->freeblock_unlock(); if (sd != NULL && battle_config.prevent_logout_trigger & PLT_ATTACK) sd->canlog_tick = timer->gettick(); diff --git a/src/plugins/HPMHooking/HPMHooking.Defs.inc b/src/plugins/HPMHooking/HPMHooking.Defs.inc index e5117e289..bd17dc7fe 100644 --- a/src/plugins/HPMHooking/HPMHooking.Defs.inc +++ b/src/plugins/HPMHooking/HPMHooking.Defs.inc @@ -6434,6 +6434,8 @@ typedef int (*HPMHOOK_pre_script_cleanfloor_sub) (struct block_list **bl, va_lis typedef int (*HPMHOOK_post_script_cleanfloor_sub) (int retVal___, struct block_list *bl, va_list ap); typedef int (*HPMHOOK_pre_script_run_func) (struct script_state **st); typedef int (*HPMHOOK_post_script_run_func) (int retVal___, struct script_state *st); +typedef bool (*HPMHOOK_pre_script_sprintf) (struct script_state **st, int *start, struct StringBuf **out); +typedef bool (*HPMHOOK_post_script_sprintf) (bool retVal___, struct script_state *st, int start, struct StringBuf *out); typedef const char* (*HPMHOOK_pre_script_getfuncname) (struct script_state **st); typedef const char* (*HPMHOOK_post_script_getfuncname) (const char* retVal___, struct script_state *st); typedef unsigned int (*HPMHOOK_pre_script_calc_hash_ci) (const char **p); diff --git a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc index 0e027043e..9d531e370 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HPMHooksCore.inc @@ -5054,6 +5054,8 @@ struct { struct HPMHookPoint *HP_script_cleanfloor_sub_post; struct HPMHookPoint *HP_script_run_func_pre; struct HPMHookPoint *HP_script_run_func_post; + struct HPMHookPoint *HP_script_sprintf_pre; + struct HPMHookPoint *HP_script_sprintf_post; struct HPMHookPoint *HP_script_getfuncname_pre; struct HPMHookPoint *HP_script_getfuncname_post; struct HPMHookPoint *HP_script_calc_hash_ci_pre; @@ -11333,6 +11335,8 @@ struct { int HP_script_cleanfloor_sub_post; int HP_script_run_func_pre; int HP_script_run_func_post; + int HP_script_sprintf_pre; + int HP_script_sprintf_post; int HP_script_getfuncname_pre; int HP_script_getfuncname_post; int HP_script_calc_hash_ci_pre; diff --git a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc index f668cfec6..5551668d2 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.HookingPoints.inc @@ -2589,6 +2589,7 @@ struct HookingPointData HookingPoints[] = { { HP_POP(script->buildin_mobuseskill_sub, HP_script_buildin_mobuseskill_sub) }, { HP_POP(script->cleanfloor_sub, HP_script_cleanfloor_sub) }, { HP_POP(script->run_func, HP_script_run_func) }, + { HP_POP(script->sprintf, HP_script_sprintf) }, { HP_POP(script->getfuncname, HP_script_getfuncname) }, { HP_POP(script->calc_hash_ci, HP_script_calc_hash_ci) }, { HP_POP(script->array_src, HP_script_array_src) }, diff --git a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc index 91c513fc0..2e20ab157 100644 --- a/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc +++ b/src/plugins/HPMHooking/HPMHooking_map.Hooks.inc @@ -67480,6 +67480,33 @@ int HP_script_run_func(struct script_state *st) { } return retVal___; } +bool HP_script_sprintf(struct script_state *st, int start, struct StringBuf *out) { + int hIndex = 0; + bool retVal___ = false; + if (HPMHooks.count.HP_script_sprintf_pre > 0) { + bool (*preHookFunc) (struct script_state **st, int *start, struct StringBuf **out); + *HPMforce_return = false; + for (hIndex = 0; hIndex < HPMHooks.count.HP_script_sprintf_pre; hIndex++) { + preHookFunc = HPMHooks.list.HP_script_sprintf_pre[hIndex].func; + retVal___ = preHookFunc(&st, &start, &out); + } + if (*HPMforce_return) { + *HPMforce_return = false; + return retVal___; + } + } + { + retVal___ = HPMHooks.source.script.sprintf(st, start, out); + } + if (HPMHooks.count.HP_script_sprintf_post > 0) { + bool (*postHookFunc) (bool retVal___, struct script_state *st, int start, struct StringBuf *out); + for (hIndex = 0; hIndex < HPMHooks.count.HP_script_sprintf_post; hIndex++) { + postHookFunc = HPMHooks.list.HP_script_sprintf_post[hIndex].func; + retVal___ = postHookFunc(retVal___, st, start, out); + } + } + return retVal___; +} const char* HP_script_getfuncname(struct script_state *st) { int hIndex = 0; const char* retVal___ = NULL; diff --git a/src/plugins/mapcache.c b/src/plugins/mapcache.c index f1dab97c1..5e44492f6 100644 --- a/src/plugins/mapcache.c +++ b/src/plugins/mapcache.c @@ -341,6 +341,100 @@ bool mapcache_rebuild(void) return true; } +bool fix_md5_truncation_sub(FILE *fp, const char *map_name) +{ + unsigned int file_size; + struct map_cache_header mheader = { 0 }; + uint8 *buf = NULL; + + nullpo_retr(false, fp); + nullpo_retr(false, map_name); + + fseek(fp, 0, SEEK_END); + file_size = (unsigned int)ftell(fp); + fseek(fp, 0, SEEK_SET); // Rewind file pointer before passing it to the read function. + + if (file_size <= sizeof(mheader) || fread(&mheader, sizeof(mheader), 1, fp) < 1) { + ShowError("fix_md5_truncation: Failed to read cache header for map '%s'.\n", map_name); + return false; + } + + if (mheader.len <= 0) { + ShowError("fix_md5_truncation: A file with negative or zero compressed length passed '%d'.\n", mheader.len); + return false; + } + + if (file_size < sizeof(mheader) + mheader.len) { + ShowError("fix_md5_truncation: An incomplete file passed for map '%s'.\n", map_name); + return false; + } + + CREATE(buf, uint8, mheader.len); + if (fread(buf, mheader.len, 1, fp) < 1) { + ShowError("fix_md5_truncation: Could not load the compressed cell data for map '%s'.\n", map_name); + aFree(buf); + return false; + } + + md5->binary(buf, mheader.len, mheader.md5_checksum); + aFree(buf); + + fseek(fp, 0, SEEK_SET); + fwrite(&mheader, sizeof(mheader), 1, fp); + fclose(fp); + + return true; +} + +bool fix_md5_truncation(void) +{ + int i; + bool retval = true; + + if (mapcache_read_maplist("db/map_index.txt") == false) { + ShowError("mapcache_rebuild: Could not read maplist, aborting\n"); + return false; + } + + for (i = 0; i < VECTOR_LENGTH(maplist); ++i) { + const char *map_name = VECTOR_INDEX(maplist, i); + char file_path[255]; + FILE *fp = NULL; + int16 version; + + snprintf(file_path, sizeof(file_path), "%s%s%s.%s", "maps/", DBPATH, map_name, "mcache"); + + fp = fopen(file_path, "r+b"); + + if (fp == NULL) { + ShowWarning("fix_md5_truncation: Could not open the mapcache file for map '%s' at path '%s'.\n", map_name, file_path); + retval = false; + continue; + } + + if (fread(&version, sizeof(version), 1, fp) < 1) { + ShowError("fix_md5_truncation: Could not read file version for map '%s'.\n", map_name); + fclose(fp); + retval = false; + continue; + } + + if (version != 1) { + ShowError("fix_md5_truncation: Mapcache for map '%s' has version %d. The update is only applied to version 1.\n", map_name, version); + fclose(fp); + continue; + } + + ShowStatus("Updating mapcache: %s'\n", map_name); + if (!fix_md5_truncation_sub(fp, map_name)) + retval = false; + + fclose(fp); + } + + return retval; +} + CMDLINEARG(convertmapcache) { map->minimal = true; @@ -363,6 +457,12 @@ CMDLINEARG(cachemap) return mapcache_cache_map(params); } +CMDLINEARG(fixmd5) +{ + map->minimal = true; + return fix_md5_truncation(); +} + HPExport void server_preinit(void) { addArg("--convert-old-mapcache", false, convertmapcache, @@ -371,6 +471,8 @@ HPExport void server_preinit(void) "Rebuilds the entire mapcache folder (maps/"DBPATH"), using db/map_index.txt as index."); addArg("--map", true, cachemap, "Rebuilds an individual map's cache into maps/"DBPATH" (usage: --map <map_name_without_extension>)."); + addArg("--fix-md5", false, fixmd5, + "Updates the checksum for the files in maps/"DBPATH", using db/map_index.txt as index (see PR #1981)."); needs_grfio = false; VECTOR_INIT(maplist); @@ -378,6 +480,10 @@ HPExport void server_preinit(void) HPExport void plugin_final(void) { + while (VECTOR_LENGTH(maplist) > 0) { + char *name = VECTOR_POP(maplist); + aFree(name); + } VECTOR_CLEAR(maplist); if (needs_grfio) grfio->final(); |