From f2d7f16d0e4162afa2dd32d1bab4e76550d8ca59 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 13:51:16 +0200 Subject: Update SQL query in char_change_sex_sub() to update character's gender and robe view ID, too --- src/char/char.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index c61b6107a..04a72fb6b 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2566,9 +2566,15 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `equip`='0' WHERE `char_id`='%d'", inventory_db, char_id)) Sql_ShowDebug(inter->sql_handle); +#if PACKETVER >= 20141016 + char gender = (sex == SEX_MALE) ? 'M' : ((sex == SEX_FEMALE) ? 'F' : 'U'); +#else + char gender = 'U'; +#endif + if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', " - "`head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", - char_db, class, char_id)) + "`head_top`='0', `head_mid`='0', `head_bottom`='0', `robe`='0', `sex`='%c' " + "WHERE `char_id`='%d' ", char_db, class, gender, char_id)) Sql_ShowDebug(inter->sql_handle); if (guild_id) // If there is a guild, update the guild_member data [Skotlex] inter_guild->sex_changed(guild_id, acc, char_id, sex); -- cgit v1.2.3-60-g2f50 From ddfdb774945e1a579d0e644ee339a88c25128f72 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 13:55:52 +0200 Subject: Remove unnecessary gender update SQL query from char_changecharsex() Gender gets updated in char_change_sex_sub() so we can safely skip it in char_changecharsex(). --- src/char/char.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 04a72fb6b..5add42e75 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3538,10 +3538,6 @@ static int char_changecharsex(int char_id, int sex) SQL->GetData(inter->sql_handle, 2, &data, NULL); guild_id = atoi(data); SQL->FreeResult(inter->sql_handle); - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `sex` = '%c' WHERE `char_id` = '%d'", char_db, sex == SEX_MALE ? 'M' : 'F', char_id)) { - Sql_ShowDebug(inter->sql_handle); - return 1; - } char_change_sex_sub(sex, account_id, char_id, class, guild_id); // disconnect player if online on char-server -- cgit v1.2.3-60-g2f50 From 76e3b302c49ebe95deb52f6c018c14f7a1da9cb2 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 15:33:07 +0200 Subject: Adjust char_change_sex_sub() to use prepared statements --- src/char/char.c | 40 ++++++++++++++++++++++++++++++++++------ 1 file changed, 34 insertions(+), 6 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 5add42e75..13ddce616 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2563,8 +2563,24 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu else if (class == JOB_KAGEROU || class == JOB_OBORO) class = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO); - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `equip`='0' WHERE `char_id`='%d'", inventory_db, char_id)) - Sql_ShowDebug(inter->sql_handle); + struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); + + /** If we can't save the data, there's nothing to do. **/ + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); + return; + } + + const char *query_inv = "UPDATE `%s` SET `equip`='0' WHERE `char_id`=?"; + + /** Don't change gender if resetting the view data fails to prevent character from being unable to login. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query_inv, inventory_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } #if PACKETVER >= 20141016 char gender = (sex == SEX_MALE) ? 'M' : ((sex == SEX_FEMALE) ? 'F' : 'U'); @@ -2572,10 +2588,22 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu char gender = 'U'; #endif - if (SQL_ERROR == SQL->Query(inter->sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', " - "`head_top`='0', `head_mid`='0', `head_bottom`='0', `robe`='0', `sex`='%c' " - "WHERE `char_id`='%d' ", char_db, class, gender, char_id)) - Sql_ShowDebug(inter->sql_handle); + const char *query_char = "UPDATE `%s` SET `class`=?, `weapon`='0', `shield`='0', `head_top`='0', " + "`head_mid`='0', `head_bottom`='0', `robe`='0', `sex`=? WHERE `char_id`=?"; + + /** Don't update guild data if changing gender fails to prevent data de-synchronisation. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query_char, char_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &class, sizeof(class)) + || SQL_ERROR == SQL->StmtBindParam(stmt, 1, SQLDT_ENUM, &gender, sizeof(gender)) + || SQL_ERROR == SQL->StmtBindParam(stmt, 2, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return; + } + + SQL->StmtFree(stmt); + if (guild_id) // If there is a guild, update the guild_member data [Skotlex] inter_guild->sex_changed(guild_id, acc, char_id, sex); } -- cgit v1.2.3-60-g2f50 From 917870695752295ec9c17ffbad746a0d99623257 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 16:02:30 +0200 Subject: Adjust char_changecharsex() to use prepared statement --- src/char/char.c | 50 ++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 40 insertions(+), 10 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 13ddce616..6eb92ba3f 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3550,21 +3550,51 @@ static void char_ask_name_ack(int fd, int acc, const char *name, int type, int r static int char_changecharsex(int char_id, int sex) { int class = 0, guild_id = 0, account_id = 0; - char *data; - // get character data - if (SQL_ERROR == SQL->Query(inter->sql_handle, "SELECT `account_id`,`class`,`guild_id` FROM `%s` WHERE `char_id` = '%d'", char_db, char_id)) { - Sql_ShowDebug(inter->sql_handle); + struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); + + /** If we can't load the data, there's nothing to do. **/ + if (stmt == NULL) { + SqlStmt_ShowDebug(stmt); return 1; } - if (SQL->NumRows(inter->sql_handle) != 1 || SQL_ERROR == SQL->NextRow(inter->sql_handle)) { - SQL->FreeResult(inter->sql_handle); + + const char *query = "SELECT `account_id`, `class`, `guild_id` FROM `%s` WHERE `char_id`=?"; + + /** Abort changing gender if there was an error while loading the data. **/ + if (SQL_ERROR == SQL->StmtPrepare(stmt, query, char_db) + || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT32, &char_id, sizeof(char_id)) + || SQL_ERROR == SQL->StmtExecute(stmt) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT32, &account_id, sizeof(account_id), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_INT32, &class, sizeof(class), NULL, NULL) + || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_INT32, &guild_id, sizeof(guild_id), NULL, NULL)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); return 1; } - SQL->GetData(inter->sql_handle, 0, &data, NULL); account_id = atoi(data); - SQL->GetData(inter->sql_handle, 1, &data, NULL); class = atoi(data); - SQL->GetData(inter->sql_handle, 2, &data, NULL); guild_id = atoi(data); - SQL->FreeResult(inter->sql_handle); + + /** Abort changing gender if no character was found. **/ + if (SQL->StmtNumRows(stmt) < 1) { + ShowError("char_changecharsex: Requested non-existant character! (ID: %d)\n", char_id); + SQL->StmtFree(stmt); + return 1; + } + + /** Abort changing gender if more than one character was found. **/ + if (SQL->StmtNumRows(stmt) > 1) { + ShowError("char_changecharsex: There are multiple characters with identical ID! (ID: %d)\n", char_id); + SQL->StmtFree(stmt); + return 1; + } + + /** Abort changing gender if fetching the data fails. **/ + if (SQL_ERROR == SQL->StmtNextRow(stmt)) { + SqlStmt_ShowDebug(stmt); + SQL->StmtFree(stmt); + return 1; + } + + SQL->StmtFree(stmt); char_change_sex_sub(sex, account_id, char_id, class, guild_id); -- cgit v1.2.3-60-g2f50 From 4f414332b9a856b4e7b66e21b54284ab0a5cf5f6 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 16:21:05 +0200 Subject: Apply code style to char_change_sex_sub() --- src/char/char.c | 52 +++++++++++++++++++++++++++------------------------- 1 file changed, 27 insertions(+), 25 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 6eb92ba3f..d3d69bd9e 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -2535,34 +2535,19 @@ static void char_changesex(int account_id, int sex) } /** - * Performs the necessary operations when changing a character's sex, such as - * correcting the job class and unequipping items, and propagating the - * information to the guild data. + * Performs the necessary operations when changing a character's gender, + * such as correcting the job class and unequipping items, + * and propagating the information to the guild data. * - * @param sex The new sex (SEX_MALE or SEX_FEMALE). - * @param acc The character's account ID. - * @param char_id The character ID. - * @param class The character's current job class. + * @param sex The character's new gender (SEX_MALE or SEX_FEMALE). + * @param acc The character's account ID. + * @param char_id The character ID. + * @param class The character's current job class. * @param guild_id The character's guild ID. - */ + * + **/ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int guild_id) { - // job modification - if (class == JOB_BARD || class == JOB_DANCER) - class = (sex == SEX_MALE ? JOB_BARD : JOB_DANCER); - else if (class == JOB_CLOWN || class == JOB_GYPSY) - class = (sex == SEX_MALE ? JOB_CLOWN : JOB_GYPSY); - else if (class == JOB_BABY_BARD || class == JOB_BABY_DANCER) - class = (sex == SEX_MALE ? JOB_BABY_BARD : JOB_BABY_DANCER); - else if (class == JOB_MINSTREL || class == JOB_WANDERER) - class = (sex == SEX_MALE ? JOB_MINSTREL : JOB_WANDERER); - else if (class == JOB_MINSTREL_T || class == JOB_WANDERER_T) - class = (sex == SEX_MALE ? JOB_MINSTREL_T : JOB_WANDERER_T); - else if (class == JOB_BABY_MINSTREL || class == JOB_BABY_WANDERER) - class = (sex == SEX_MALE ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); - else if (class == JOB_KAGEROU || class == JOB_OBORO) - class = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO); - struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); /** If we can't save the data, there's nothing to do. **/ @@ -2582,6 +2567,22 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu return; } + /** Correct the job class for gender specific jobs according to the passed gender. **/ + if (class == JOB_BARD || class == JOB_DANCER) + class = (sex == SEX_MALE ? JOB_BARD : JOB_DANCER); + else if (class == JOB_CLOWN || class == JOB_GYPSY) + class = (sex == SEX_MALE ? JOB_CLOWN : JOB_GYPSY); + else if (class == JOB_BABY_BARD || class == JOB_BABY_DANCER) + class = (sex == SEX_MALE ? JOB_BABY_BARD : JOB_BABY_DANCER); + else if (class == JOB_MINSTREL || class == JOB_WANDERER) + class = (sex == SEX_MALE ? JOB_MINSTREL : JOB_WANDERER); + else if (class == JOB_MINSTREL_T || class == JOB_WANDERER_T) + class = (sex == SEX_MALE ? JOB_MINSTREL_T : JOB_WANDERER_T); + else if (class == JOB_BABY_MINSTREL || class == JOB_BABY_WANDERER) + class = (sex == SEX_MALE ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER); + else if (class == JOB_KAGEROU || class == JOB_OBORO) + class = (sex == SEX_MALE ? JOB_KAGEROU : JOB_OBORO); + #if PACKETVER >= 20141016 char gender = (sex == SEX_MALE) ? 'M' : ((sex == SEX_FEMALE) ? 'F' : 'U'); #else @@ -2604,7 +2605,8 @@ static void char_change_sex_sub(int sex, int acc, int char_id, int class, int gu SQL->StmtFree(stmt); - if (guild_id) // If there is a guild, update the guild_member data [Skotlex] + /** Update guild member data if a guild ID was passed. **/ + if (guild_id != 0) inter_guild->sex_changed(guild_id, acc, char_id, sex); } -- cgit v1.2.3-60-g2f50 From 605014f8ad2b5410f85155682c8c483c4bec4568 Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Mon, 6 Jul 2020 16:27:46 +0200 Subject: Apply code style to char_changecharsex() --- src/char/char.c | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index d3d69bd9e..8e69b1738 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3540,19 +3540,17 @@ static void char_ask_name_ack(int fd, int acc, const char *name, int type, int r } /** - * Changes a character's sex. - * The information is updated on database, and the character is kicked if it - * currently is online. + * Changes a character's gender. + * The information is updated on database, and the character is kicked if it currently is online. * - * @param char_id The character's ID. - * @param sex The new sex. + * @param char_id The character ID + * @param sex The character's new gender (SEX_MALE or SEX_FEMALE). * @retval 0 in case of success. * @retval 1 in case of failure. - */ + * + **/ static int char_changecharsex(int char_id, int sex) { - int class = 0, guild_id = 0, account_id = 0; - struct SqlStmt *stmt = SQL->StmtMalloc(inter->sql_handle); /** If we can't load the data, there's nothing to do. **/ @@ -3562,6 +3560,9 @@ static int char_changecharsex(int char_id, int sex) } const char *query = "SELECT `account_id`, `class`, `guild_id` FROM `%s` WHERE `char_id`=?"; + int account_id; + int class; + int guild_id; /** Abort changing gender if there was an error while loading the data. **/ if (SQL_ERROR == SQL->StmtPrepare(stmt, query, char_db) @@ -3597,14 +3598,10 @@ static int char_changecharsex(int char_id, int sex) } SQL->StmtFree(stmt); - char_change_sex_sub(sex, account_id, char_id, class, guild_id); + chr->disconnect_player(account_id); // Disconnect player if online on char-server. + chr->changesex(account_id, sex); // Notify all mapservers about this change. - // disconnect player if online on char-server - chr->disconnect_player(account_id); - - // notify all mapservers about this change - chr->changesex(account_id, sex); return 0; } -- cgit v1.2.3-60-g2f50 From 4a8b9f6998fa936545beece9c3c6b4d3c73babde Mon Sep 17 00:00:00 2001 From: Kenpachi Developer Date: Tue, 7 Jul 2020 09:55:20 +0200 Subject: Reapply initial values in char_changecharsex() --- src/char/char.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/char/char.c b/src/char/char.c index 8e69b1738..b3de22c00 100644 --- a/src/char/char.c +++ b/src/char/char.c @@ -3560,9 +3560,9 @@ static int char_changecharsex(int char_id, int sex) } const char *query = "SELECT `account_id`, `class`, `guild_id` FROM `%s` WHERE `char_id`=?"; - int account_id; - int class; - int guild_id; + int account_id = 0; + int class = 0; + int guild_id = 0; /** Abort changing gender if there was an error while loading the data. **/ if (SQL_ERROR == SQL->StmtPrepare(stmt, query, char_db) -- cgit v1.2.3-60-g2f50