The crash happens in this function, but is not the fault of this function, just a symptom of the problem. As is obvious at the last several pages of the log, this crash is happening because the Database is being dropped and unable to perform queries. This causes HandleCharacterSelected() to fail. I have added a countermeasure to prevent a crash in HandleCharacterSelected(), but this does not resolve the reason the database is being dropped (I don't have better terminology for what's happening):
Code: Select all
22:42:16.034 E Database Error running MySQL query (2013): Lost connection to MySQL server during query
DELETE FROM `character_titles` WHERE char_id_fk=619
22:42:16.034 E Char SaveCharacter: Failed to save character titles at c:\vgoemu\src\world\worlddatabase.cpp:2061
I'll post the 2 functions where this may be happening. These may or may not be the culprit. It either hangs on the previous query, which is:
Code: Select all
bool WorldDatabase::SaveCharacterDetails(shared_ptr<WorldCharacter>& character) {
bool result = false;
if (!character) {
return(false);
}
result = database.Query("UPDATE `character_details` "
"SET `title_show`=%d, `title_prefix`=%d, `title_suffix`=%d "
"WHERE char_id_fk=%u", character->GetTitleShow(), character->GetTitleCurrentPrefix(), character->GetTitleCurrentSuffix(), character->GetCharacterID());
if (!result) {
return(false);
}
return(true);
}
Code: Select all
bool WorldDatabase::SaveCharacterTitles(shared_ptr<WorldCharacter>& character) {
uint32_t char_id = 0;
vector<uint32_t> titles;
string query;
char buffer[64]; // Must be long enough to hold all of the data below
bool result = false;
if (!character) {
return(false);
}
// Drop all titles for this character, this allows for removing a title
result = database.Query("DELETE FROM `character_titles` WHERE char_id_fk=%d", character->GetCharacterID());
if (!result) {
return(false);
}
// Just return if there are no titles to save
if (character->GetTitleCount() == 0) {
return(true);
}
// Get some info
titles = character->GetTitles();
char_id = character->GetCharacterID();
// Start the query string
query = "INSERT IGNORE INTO `character_titles` (`char_id_fk`,`title_id_fk`) VALUES ";
// Add all of the character titles to the query string
for (uint32_t i=0; i<character->GetTitleCount(); i++) {
snprintf(buffer, sizeof(buffer), "('%d','%d'),", char_id, titles.at(i));
query.append(buffer);
}
query.pop_back();
// Run the query
result = database.Query(query.c_str());
if (!result) {
return(false);
}
return(true);
}
Another thing I noticed is that the WorldCharacter object being processed at the time of these failures is empty, or incomplete in some way. This is indicated by this failure, right after these query failures:
Code: Select all
22:42:16.050 E Char SaveCharacter: Failed to get character chunk at c:\vgoemu\src\world\worlddatabase.cpp:2083
This means we are unable to get the WorldCharacter's chunk, used in this failure reporting section:
Code: Select all
if (error && character->GetIsOnline()) {
// We need to tell the client if there was a failure, the real game did
chunk = character->GetCurrentChunk();
if (!chunk) {
LogError(LOG_CHARACTER, 0, "SaveCharacter: Failed to get character chunk at %s:%u", __FILE__, __LINE__);
return;
}
chunk_client = chunk->GetClient(character->GetAccountID());
if (!chunk_client) {
LogError(LOG_CHARACTER, 0, "SaveCharacter: Failed to get character client at %s:%u", __FILE__, __LINE__);
return;
}
// Now send the error message
chunk_client->SendMessageFromServer("<color=red>Failed to save your character. You should relog now.");
}
else {
// Set to log_level 2 because with many players it will get spammy
LogDebug(LOG_CHARACTER, 2, "Saved character '%s' (%u) data.", character->GetDisplayName().c_str(), character->GetCharacterID());
}
Somewhere along the way, the WorldCharacter object is being used while being empty. As mentioned, Commit 888 resolves one crash possibility, but NOT the fact that these queries all start to fail at some point.