diff --git a/common/database.cpp b/common/database.cpp index b90340ad9..92df542f8 100644 --- a/common/database.cpp +++ b/common/database.cpp @@ -80,7 +80,7 @@ bool Database::Connect(const char* host, const char* user, const char* passwd, c LogFile->write(EQEMuLog::Error, "Failed to connect to database: Error: %s", errbuf); HandleMysqlError(errnum); - return false; + return false; } else { @@ -555,7 +555,7 @@ bool Database::DeleteCharacter(char *name) return true; } -// Store new character information into the character_ and inventory tables +/* This only for new Character creation storing */ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext) { char query[256+sizeof(PlayerProfile_Struct)*2+sizeof(ExtendedProfile_Struct)*2+5]; @@ -639,7 +639,6 @@ bool Database::StoreCharacter(uint32 account_id, PlayerProfile_Struct* pp, Inven i++; } - return true; } @@ -772,8 +771,7 @@ void Database::GetCharName(uint32 char_id, char* name) { strcpy(name, row[0]); } -static inline void loadbar(unsigned int x, unsigned int n, unsigned int w = 50) -{ +static inline void loadbar(unsigned int x, unsigned int n, unsigned int w = 50) { if ((x != n) && (x % (n / 100 + 1) != 0)) return; float ratio = x / (float)n; @@ -787,31 +785,46 @@ static inline void loadbar(unsigned int x, unsigned int n, unsigned int w = 50) bool Database::CheckDatabaseConversions() { /* Set all of this ugliness */ - char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf2[MYSQL_ERRMSG_SIZE]; - char *query = 0; char *query2 = 0; - uint32 querylen; uint32 querylen2; - MYSQL_RES *result; MYSQL_RES *result2; - MYSQL_ROW row2; MYSQL_ROW row; + char errbuf[MYSQL_ERRMSG_SIZE]; char errbuf2[MYSQL_ERRMSG_SIZE]; char errbuf3[MYSQL_ERRMSG_SIZE]; + char *query = 0; char *query2 = 0; char *query3 = 0; + uint32 querylen; uint32 querylen2; uint32 querylen3; + MYSQL_RES *result; MYSQL_RES *result2; MYSQL_RES *result3; + MYSQL_ROW row; MYSQL_ROW row2; MYSQL_ROW row3; unsigned long* lengths; PlayerProfile_Struct* pp; uint32 pplen = 0; uint32 i; - + int character_id = 0; + int account_id = 0; int number_of_characters = 0; - int printppdebug = 1; + int printppdebug = 0; int runconvert = 0; - printf("CheckDatabase Running.... \n"); + /* Check For Legacy Storage Method */ + std::string rquery = StringFormat("SELECT `profile` FROM `character_` LIMIT 1"); + auto results = QueryDatabase(rquery); + for (auto row = results.begin(); row != results.end(); ++row) { + runconvert = 1; + printf("\n\n::: Legacy Character Data Binary Blob Storage Detected... \n"); + printf("----------------------------------------------------------\n\n"); + printf(" Database currently has character data being stored via \n"); + printf(" the legacy character storage method and will proceed with converting...\n\n"); + printf(" It is recommended that you backup your database \n"); + printf(" before continuing the automatic conversion proces...\n\n"); + printf("----------------------------------------------------------\n\n"); + std::cout << "Press ENTER to continue....." << std::endl << std::endl; + std::cin.ignore(1); + } - printf("Running character binary blob to database conversion... \n", number_of_characters); - /* Get the number of characters */ - querylen = MakeAnyLenString(&query, "SELECT COUNT(`id`) FROM `character_`"); - if (RunQuery(query, querylen, errbuf, &result)) { - row = mysql_fetch_row(result); - number_of_characters = atoi(row[0]); - printf("Number of Characters in Database: %i \n", number_of_characters); - safe_delete_array(query); - mysql_free_result(result); + if (runconvert == 1){ + printf("Running character binary blob to database conversion... \n", number_of_characters); + /* Get the number of characters */ + rquery = StringFormat("SELECT COUNT(`id`) FROM `character_`"); + results = QueryDatabase(rquery); + for (auto row = results.begin(); row != results.end(); ++row) { + number_of_characters = atoi(row[0]); + printf("Number of Characters in Database: %i \n", number_of_characters); + } } // querylen = MakeAnyLenString(&query, "SELECT `id` FROM `character_` WHERE `id` = 61238"); @@ -821,12 +834,13 @@ bool Database::CheckDatabaseConversions() { safe_delete_array(query); while (row = mysql_fetch_row(result)) { char_iter_count++; - querylen2 = MakeAnyLenString(&query2, "SELECT `id`, `profile`, `name`, `level` FROM `character_` WHERE `id` = %i", atoi(row[0])); + querylen2 = MakeAnyLenString(&query2, "SELECT `id`, `profile`, `name`, `level`, `account_id` FROM `character_` WHERE `id` = %i", atoi(row[0])); if (RunQuery(query2, querylen2, errbuf2, &result2)){ safe_delete_array(query2); row2 = mysql_fetch_row(result2); - pp = (PlayerProfile_Struct*)row2[1]; - + pp = (PlayerProfile_Struct*)row2[1]; + character_id = atoi(row[0]); + account_id = atoi(row2[4]); /* Verify PP Integrity */ lengths = mysql_fetch_lengths(result2); if (lengths[1] == sizeof(PlayerProfile_Struct)) { @@ -842,11 +856,325 @@ bool Database::CheckDatabaseConversions() { /* Loading Status on conversion */ if (runconvert == 1){ std::cout << "\r" << char_iter_count << "/" << number_of_characters << " " << std::flush; - loadbar(char_iter_count, number_of_characters, 50); + loadbar(char_iter_count, number_of_characters, 50); + + /* Run Currency Convert */ + std::string rquery = StringFormat("REPLACE INTO `character_currency` (id, platinum, gold, silver, copper," + "platinum_bank, gold_bank, silver_bank, copper_bank," + "platinum_cursor, gold_cursor, silver_cursor, copper_cursor, " + "radiant_crystals, career_radiant_crystals, ebon_crystals, career_ebon_crystals)" + "VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u)", + character_id, + pp->platinum, + pp->gold, + pp->silver, + pp->copper, + pp->platinum_bank, + pp->gold_bank, + pp->silver_bank, + pp->copper_bank, + pp->platinum_cursor, + pp->gold_cursor, + pp->silver_cursor, + pp->copper_cursor, + pp->currentRadCrystals, + pp->careerRadCrystals, + pp->currentEbonCrystals, + pp->careerEbonCrystals + ); + auto results = QueryDatabase(rquery); + + /* Run Character Data Convert */ + rquery = StringFormat( + "REPLACE INTO `character_data` (" + " id, " + " account_id, " + " `name`, " + " last_name, " + " gender, " + " race, " + " class, " + " `level`, " + " deity, " + " birthday, " + " last_login, " + " time_played, " + " pvp_status, " + " level2, " + " anon, " + " gm, " + " intoxication, " + " hair_color, " + " beard_color, " + " eye_color_1, " + " eye_color_2, " + " hair_style, " + " beard, " + " ability_time_seconds, " + " ability_number, " + " ability_time_minutes, " + " ability_time_hours, " + " title, " + " suffix, " + " exp, " + " points, " + " mana, " + " cur_hp, " + " str, " + " sta, " + " cha, " + " dex, " + " `int`, " + " agi, " + " wis, " + " face, " + " y, " + " x, " + " z, " + " heading, " + " pvp2, " + " pvp_type, " + " autosplit_enabled, " + " zone_change_count, " + " drakkin_heritage, " + " drakkin_tattoo, " + " drakkin_details, " + " toxicity, " + " hunger_level, " + " thirst_level, " + " ability_up, " + " zone_id, " + " zone_instance, " + " leadership_exp_on, " + " ldon_points_guk, " + " ldon_points_mir, " + " ldon_points_mmc, " + " ldon_points_ruj, " + " ldon_points_tak, " + " ldon_points_available, " + " tribute_time_remaining, " + " show_helm, " + " career_tribute_points, " + " tribute_points, " + " tribute_active, " + " endurance, " + " group_leadership_exp, " + " raid_leadership_exp, " + " group_leadership_points, " + " raid_leadership_points, " + " air_remaining, " + " pvp_kills, " + " pvp_deaths, " + " pvp_current_points, " + " pvp_career_points, " + " pvp_best_kill_streak, " + " pvp_worst_death_streak, " + " pvp_current_kill_streak, " + " aa_points_spent, " + " aa_exp, " + " aa_points, " + " group_auto_consent, " + " raid_auto_consent, " + " guild_auto_consent, " + " RestTimer) " + "VALUES (" + "%u," // id " id, " + "%u," // account_id " account_id, " + "'%s'," // `name` pp->name, " `name`, " + "'%s'," // last_name pp->last_name, " last_name, " + "%u," // gender pp->gender, " gender, " + "%u," // race pp->race, " race, " + "%u," // class pp->class_, " class, " + "%u," // `level` pp->level, " `level`, " + "%u," // deity pp->deity, " deity, " + "%u," // birthday pp->birthday, " birthday, " + "%u," // last_login pp->lastlogin, " last_login, " + "%u," // time_played pp->timePlayedMin, " time_played, " + "%u," // pvp_status pp->pvp, " pvp_status, " + "%u," // level2 pp->level2, " level2, " + "%u," // anon pp->anon, " anon, " + "%u," // gm pp->gm, " gm, " + "%u," // intoxication pp->intoxication, " intoxication, " + "%u," // hair_color pp->haircolor, " hair_color, " + "%u," // beard_color pp->beardcolor, " beard_color, " + "%u," // eye_color_1 pp->eyecolor1, " eye_color_1, " + "%u," // eye_color_2 pp->eyecolor2, " eye_color_2, " + "%u," // hair_style pp->hairstyle, " hair_style, " + "%u," // beard pp->beard, " beard, " + "%u," // ability_time_seconds pp->ability_time_seconds, " ability_time_seconds, " + "%u," // ability_number pp->ability_number, " ability_number, " + "%u," // ability_time_minutes pp->ability_time_minutes, " ability_time_minutes, " + "%u," // ability_time_hours pp->ability_time_hours, " ability_time_hours, " + "'%s'," // title pp->title, " title, " + "'%s'," // suffix pp->suffix, " suffix, " + "%u," // exp pp->exp, " exp, " + "%u," // points pp->points, " points, " + "%u," // mana pp->mana, " mana, " + "%u," // cur_hp pp->cur_hp, " cur_hp, " + "%u," // str pp->STR, " str, " + "%u," // sta pp->STA, " sta, " + "%u," // cha pp->CHA, " cha, " + "%u," // dex pp->DEX, " dex, " + "%u," // `int` pp->INT, " `int`, " + "%u," // agi pp->AGI, " agi, " + "%u," // wis pp->WIS, " wis, " + "%u," // face pp->face, " face, " + "%f," // y pp->y, " y, " + "%f," // x pp->x, " x, " + "%f," // z pp->z, " z, " + "%f," // heading pp->heading, " heading, " + "%u," // pvp2 pp->pvp2, " pvp2, " + "%u," // pvp_type pp->pvptype, " pvp_type, " + "%u," // autosplit_enabled pp->autosplit, " autosplit_enabled, " + "%u," // zone_change_count pp->zone_change_count, " zone_change_count, " + "%u," // drakkin_heritage pp->drakkin_heritage, " drakkin_heritage, " + "%u," // drakkin_tattoo pp->drakkin_tattoo, " drakkin_tattoo, " + "%u," // drakkin_details pp->drakkin_details, " drakkin_details, " + "%u," // toxicity pp->toxicity, " toxicity, " + "%u," // hunger_level pp->hunger_level, " hunger_level, " + "%u," // thirst_level pp->thirst_level, " thirst_level, " + "%u," // ability_up pp->ability_up, " ability_up, " + "%u," // zone_id pp->zone_id, " zone_id, " + "%u," // zone_instance pp->zoneInstance, " zone_instance, " + "%u," // leadership_exp_on pp->leadAAActive, " leadership_exp_on, " + "%u," // ldon_points_guk pp->ldon_points_guk, " ldon_points_guk, " + "%u," // ldon_points_mir pp->ldon_points_mir, " ldon_points_mir, " + "%u," // ldon_points_mmc pp->ldon_points_mmc, " ldon_points_mmc, " + "%u," // ldon_points_ruj pp->ldon_points_ruj, " ldon_points_ruj, " + "%u," // ldon_points_tak pp->ldon_points_tak, " ldon_points_tak, " + "%u," // ldon_points_available pp->ldon_points_available, " ldon_points_available, " + "%u," // tribute_time_remaining pp->tribute_time_remaining, " tribute_time_remaining, " + "%u," // show_helm pp->showhelm, " show_helm, " + "%u," // career_tribute_points pp->career_tribute_points, " career_tribute_points, " + "%u," // tribute_points pp->tribute_points, " tribute_points, " + "%u," // tribute_active pp->tribute_active, " tribute_active, " + "%u," // endurance pp->endurance, " endurance, " + "%u," // group_leadership_exp pp->group_leadership_exp, " group_leadership_exp, " + "%u," // raid_leadership_exp pp->raid_leadership_exp, " raid_leadership_exp, " + "%u," // group_leadership_points pp->group_leadership_points, " group_leadership_points, " + "%u," // raid_leadership_points pp->raid_leadership_points, " raid_leadership_points, " + "%u," // air_remaining pp->air_remaining, " air_remaining, " + "%u," // pvp_kills pp->PVPKills, " pvp_kills, " + "%u," // pvp_deaths pp->PVPDeaths, " pvp_deaths, " + "%u," // pvp_current_points pp->PVPCurrentPoints, " pvp_current_points, " + "%u," // pvp_career_points pp->PVPCareerPoints, " pvp_career_points, " + "%u," // pvp_best_kill_streak pp->PVPBestKillStreak, " pvp_best_kill_streak, " + "%u," // pvp_worst_death_streak pp->PVPWorstDeathStreak, " pvp_worst_death_streak, " + "%u," // pvp_current_kill_streak pp->PVPCurrentKillStreak, " pvp_current_kill_streak, " + "%u," // aa_points_spent pp->aapoints_spent, " aa_points_spent, " + "%u," // aa_exp pp->expAA, " aa_exp, " + "%u," // aa_points pp->aapoints, " aa_points, " + "%u," // group_auto_consent pp->groupAutoconsent, " group_auto_consent, " + "%u," // raid_auto_consent pp->raidAutoconsent, " raid_auto_consent, " + "%u," // guild_auto_consent pp->guildAutoconsent, " guild_auto_consent, " + "%u" // RestTimer pp->RestTimer, " RestTimer) " + ")", + character_id, + account_id, + pp->name, + pp->last_name, + pp->gender, + pp->race, + pp->class_, + pp->level, + pp->deity, + pp->birthday, + pp->lastlogin, + pp->timePlayedMin, + pp->pvp, + pp->level2, + pp->anon, + pp->gm, + pp->intoxication, + pp->haircolor, + pp->beardcolor, + pp->eyecolor1, + pp->eyecolor2, + pp->hairstyle, + pp->beard, + pp->ability_time_seconds, + pp->ability_number, + pp->ability_time_minutes, + pp->ability_time_hours, + pp->title, + pp->suffix, + pp->exp, + pp->points, + pp->mana, + pp->cur_hp, + pp->STR, + pp->STA, + pp->CHA, + pp->DEX, + pp->INT, + pp->AGI, + pp->WIS, + pp->face, + pp->y, + pp->x, + pp->z, + pp->heading, + pp->pvp2, + pp->pvptype, + pp->autosplit, + pp->zone_change_count, + pp->drakkin_heritage, + pp->drakkin_tattoo, + pp->drakkin_details, + pp->toxicity, + pp->hunger_level, + pp->thirst_level, + pp->ability_up, + pp->zone_id, + pp->zoneInstance, + pp->leadAAActive, + pp->ldon_points_guk, + pp->ldon_points_mir, + pp->ldon_points_mmc, + pp->ldon_points_ruj, + pp->ldon_points_tak, + pp->ldon_points_available, + pp->tribute_time_remaining, + pp->showhelm, + pp->career_tribute_points, + pp->tribute_points, + pp->tribute_active, + pp->endurance, + pp->group_leadership_exp, + pp->raid_leadership_exp, + pp->group_leadership_points, + pp->raid_leadership_points, + pp->air_remaining, + pp->PVPKills, + pp->PVPDeaths, + pp->PVPCurrentPoints, + pp->PVPCareerPoints, + pp->PVPBestKillStreak, + pp->PVPWorstDeathStreak, + pp->PVPCurrentKillStreak, + pp->aapoints_spent, + pp->expAA, + pp->aapoints, + pp->groupAutoconsent, + pp->raidAutoconsent, + pp->guildAutoconsent, + pp->RestTimer + ); + results = QueryDatabase(rquery); + /* Run AA Convert */ + for (i = 0; i < MAX_PP_AA_ARRAY; i++){ + if (pp->aa_array[i].AA > 0 && pp->aa_array[i].value > 0){ + std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value)" + " VALUES (%u, %u, %u, %u)", + character_id, i, pp->aa_array[i].AA, pp->aa_array[i].value); + auto results = QueryDatabase(rquery); + } + } + printf("\n\nCharacter blob conversion complete, continuing world bootup...\n"); } /* Print out the entire Player Profile for testing */ - if (printppdebug == 1){ + if (printppdebug == 1) { printf("ID: %i \n", atoi(row[0])); printf("checksum: %i \n", pp->checksum); printf("name: %s \n", pp->name); @@ -947,7 +1275,7 @@ bool Database::CheckDatabaseConversions() { printf("\n=== mem_spells[MAX_PP_MEMSPELL] ===\n"); for (i = 0; i < MAX_PP_MEMSPELL; i++){ - printf("ID: %u Value: %u \n", i, pp->mem_spells[i]); + printf("ID: %u Value: %u \n", i, pp->mem_spells[i]); } printf("\n\n"); @@ -957,6 +1285,7 @@ bool Database::CheckDatabaseConversions() { printf("z: %4.2f \n", pp->z); printf("heading: %4.2f \n", pp->heading); printf("unknown4752[4]: %u \n", pp->unknown4752[4]); + printf("platinum: %u \n", pp->platinum); printf("gold: %u \n", pp->gold); printf("silver: %u \n", pp->silver); @@ -972,6 +1301,8 @@ bool Database::CheckDatabaseConversions() { printf("platinum_shared: %u \n", pp->platinum_shared); printf("unknown4808[24]: %u \n", pp->unknown4808[24]); + + printf("\n=== skills[MAX_PP_SKILL] ===\n"); for (i = 0; i < MAX_PP_SKILL; i++){ printf("ID: %u Value: %u \n", i, pp->skills[i]); @@ -1140,7 +1471,7 @@ bool Database::CheckDatabaseConversions() { printf("unknown19568[8]: %u \n", pp->unknown19568[8]); printf("currentRadCrystals: %u \n", pp->currentRadCrystals); - printf("careerRadCrystals: %u \n", pp->careerRadCrystals); + printf("careerRadCrystals: %u \n", pp->careerRadCrystals); printf("currentEbonCrystals: %u \n", pp->currentEbonCrystals); printf("careerEbonCrystals: %u \n", pp->careerEbonCrystals); printf("groupAutoconsent: %u \n", pp->groupAutoconsent); diff --git a/common/debug.h b/common/debug.h index 6184e4cbc..5e2fff368 100644 --- a/common/debug.h +++ b/common/debug.h @@ -80,14 +80,15 @@ public: ~EQEMuLog(); enum LogIDs { - Status = 0, //this must stay the first entry in this list - Normal, - Error, - Debug, - Quest, - Commands, - Crash, - MaxLogID + Status = 0, /* This must stay the first entry in this list */ + Normal, /* Normal Logs */ + Error, /* Error Logs */ + Debug, /* Debug Logs */ + Quest, /* Quest Logs */ + Commands, /* Issued Comamnds */ + Crash, /* Crash Logs */ + Save, /* Client Saves */ + MaxLogID /* Max, used in functions to get the max log ID */ }; //these are callbacks called for each @@ -113,6 +114,7 @@ private: Mutex MOpen; Mutex MLog[MaxLogID]; FILE* fp[MaxLogID]; + /* LogStatus: bitwise variable 1 = output to file 2 = output to stdout diff --git a/common/shareddb.cpp b/common/shareddb.cpp index 8e999da54..c10e87856 100644 --- a/common/shareddb.cpp +++ b/common/shareddb.cpp @@ -1,6 +1,7 @@ #include #include #include +#include #include "shareddb.h" #include "mysql.h" @@ -1270,9 +1271,11 @@ bool SharedDatabase::SetPlayerProfile(uint32 account_id, uint32 charid, PlayerPr uint32 affected_rows = 0; bool ret = false; + clock_t t = std::clock(); /* Function timer start */ if (RunQuery(query, SetPlayerProfile_MQ(&query, account_id, charid, pp, inv, ext, current_zone, current_instance, MaxXTargets), errbuf, 0, &affected_rows)) { ret = (affected_rows != 0); } + LogFile->write(EQEMuLog::Status, "SharedDatabase::SetPlayerProfile SetPlayerProfile_MQ done... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); if (!ret) { LogFile->write(EQEMuLog::Error, "SetPlayerProfile query '%s' %s", query, errbuf); @@ -1292,7 +1295,7 @@ uint32 SharedDatabase::SetPlayerProfile_MQ(char** query, uint32 account_id, uint if (!current_instance) current_instance = pp->zoneInstance; - if(strlen(pp->name) == 0) // Sanity check in case pp never loaded + if(strlen(pp->name) == 0) /* Sanity check in case pp never loaded */ return false; end += sprintf(end, "UPDATE character_ SET timelaston=unix_timestamp(now()),name=\'%s\', zonename=\'%s\', zoneid=%u, instanceid=%u, x = %f, y = %f, z = %f, profile=\'", pp->name, GetZoneName(current_zone), current_zone, current_instance, pp->x, pp->y, pp->z); diff --git a/world/net.cpp b/world/net.cpp index f308fc1be..2d186c1af 100644 --- a/world/net.cpp +++ b/world/net.cpp @@ -222,9 +222,8 @@ int main(int argc, char** argv) { else if (strcasecmp(argv[1], "flag") == 0) { if (argc == 4) { if (Seperator::IsNumber(argv[3])) { - if (atoi(argv[3]) >= 0 && atoi(argv[3]) <= 255) { - if (database.SetAccountStatus(argv[2], atoi(argv[3]))) { + if (database.SetAccountStatus(argv[2], atoi(argv[3]))){ std::cout << "Account flagged: Username='" << argv[2] << "', status=" << argv[3] << std::endl; return 0; } @@ -277,8 +276,7 @@ int main(int argc, char** argv) { } _log(WORLD__INIT, "Checking Database Conversions.."); - database.CheckDatabaseConversions(); - + database.CheckDatabaseConversions(); _log(WORLD__INIT, "Loading variables.."); database.LoadVariables(); _log(WORLD__INIT, "Loading zones.."); diff --git a/zone/aa.cpp b/zone/aa.cpp index 2964dc6f3..390174cf5 100644 --- a/zone/aa.cpp +++ b/zone/aa.cpp @@ -1048,8 +1048,12 @@ void Client::BuyAA(AA_Action* action) mlog(AA__MESSAGE, "Set AA %d to level %d", aa2->id, cur_level + 1); m_pp.aapoints -= real_cost; + + /* Do Player Profile rank calculations and set player profile */ + SaveAA(); + /* Save to Database to avoid having to write the whole AA array to the profile, only write changes*/ + // database.SaveCharacterAA(this->CharacterID(), aa2->id, (cur_level + 1)); - Save(); if ((RuleB(AA, Stacking) && (GetClientVersionBit() >= 4) && (aa2->hotkey_sid == 4294967295u)) && ((aa2->max_level == (cur_level + 1)) && aa2->sof_next_id)){ SendAA(aa2->id); diff --git a/zone/client.cpp b/zone/client.cpp index 37740b472..0065d31c5 100644 --- a/zone/client.cpp +++ b/zone/client.cpp @@ -479,60 +479,27 @@ void Client::ReportConnectingState() { }; } -bool Client::Save(uint8 iCommitNow) { -#if 0 -// Orig. Offset: 344 / 0x00000000 -// Length: 36 / 0x00000024 - unsigned char rawData[36] = +inline double clock_diff_to_sec(long clock_diff) { - 0x0D, 0x30, 0xE1, 0x30, 0x1E, 0x10, 0x22, 0x10, 0x20, 0x10, 0x21, 0x10, 0x1C, 0x20, 0x1F, 0x10, - 0x7C, 0x10, 0x68, 0x10, 0x51, 0x10, 0x78, 0x10, 0xBD, 0x10, 0xD2, 0x10, 0xCD, 0x10, 0xD1, 0x10, - 0x01, 0x10, 0x6D, 0x10 -} ; - for (int tmp = 0;tmp <=35;tmp++){ - m_pp.unknown0256[89+tmp] = rawData[tmp]; - } -#endif + return double(clock_diff) / CLOCKS_PER_SEC; +} - if(!ClientDataLoaded()) - return false; - - m_pp.x = x_pos; - m_pp.y = y_pos; - m_pp.z = z_pos; - m_pp.guildrank=guildrank; - m_pp.heading = heading; - - // Temp Hack for signed values until we get the root of the problem changed over to signed... - if (m_pp.copper < 0) { m_pp.copper = 0; } - if (m_pp.silver < 0) { m_pp.silver = 0; } - if (m_pp.gold < 0) { m_pp.gold = 0; } - if (m_pp.platinum < 0) { m_pp.platinum = 0; } - if (m_pp.copper_bank < 0) { m_pp.copper_bank = 0; } - if (m_pp.silver_bank < 0) { m_pp.silver_bank = 0; } - if (m_pp.gold_bank < 0) { m_pp.gold_bank = 0; } - if (m_pp.platinum_bank < 0) { m_pp.platinum_bank = 0; } - - - int spentpoints=0; - for(int a=0;a < MAX_PP_AA_ARRAY;a++) { +bool Client::SaveAA(){ + clock_t t = std::clock(); /* Function timer start */ + /* Save Player AA */ + int spentpoints = 0; + for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { uint32 points = aa[a]->value; - if(points > HIGHEST_AA_VALUE) // Unifying this - { + if (points > HIGHEST_AA_VALUE) { aa[a]->value = HIGHEST_AA_VALUE; points = HIGHEST_AA_VALUE; } - if (points > 0) - { - SendAA_Struct* curAA = zone->FindAA(aa[a]->AA-aa[a]->value+1); - if(curAA) - { - for (int rank=0; rank::iterator RequiredLevel = AARequiredLevelAndCost.find(aa[a]->AA-aa[a]->value + 1 + rank); - - if(RequiredLevel != AARequiredLevelAndCost.end()) - { + if (points > 0) { + SendAA_Struct* curAA = zone->FindAA(aa[a]->AA - aa[a]->value + 1); + if (curAA) { + for (int rank = 0; rank::iterator RequiredLevel = AARequiredLevelAndCost.find(aa[a]->AA - aa[a]->value + 1 + rank); + if (RequiredLevel != AARequiredLevelAndCost.end()) { spentpoints += RequiredLevel->second.Cost; } else @@ -541,36 +508,58 @@ bool Client::Save(uint8 iCommitNow) { } } } - - m_pp.aapoints_spent = spentpoints + m_epp.expended_aa; - - if (GetHP() <= 0) { - m_pp.cur_hp = GetMaxHP(); + m_pp.aapoints_spent = spentpoints + m_epp.expended_aa; + for (int a = 0; a < MAX_PP_AA_ARRAY; a++) { + if (aa[a]->AA > 0 && aa[a]->value){ + std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, slot, aa_id, aa_value)" + " VALUES (%u, %u, %u, %u)", + character_id, a, aa[a]->AA, aa[a]->value); + auto results = database.QueryDatabase(rquery); + } } - else - m_pp.cur_hp = GetHP(); + LogFile->write(EQEMuLog::Status, "Issuing Client AA Save... CID: %i Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + return true; +} + +bool Client::Save(uint8 iCommitNow) { + if(!ClientDataLoaded()) + return false; + + clock_t t = std::clock(); /* Function timer start */ + + /* Wrote current basics to PP for saves */ + m_pp.x = x_pos; + m_pp.y = y_pos; + m_pp.z = z_pos; + m_pp.guildrank = guildrank; + m_pp.heading = heading; + + /* Mana and HP */ + if (GetHP() <= 0) { m_pp.cur_hp = GetMaxHP(); } + else { m_pp.cur_hp = GetHP(); } m_pp.mana = cur_mana; m_pp.endurance = cur_end; + /* Save Character Currency */ + database.SaveCharacterCurrency(this->CharacterID(), &m_pp); + + /* Save Character AA */ + SaveAA(); + + /* Save Character Buffs */ database.SaveBuffs(this); + /* Total Time Played */ TotalSecondsPlayed += (time(nullptr) - m_pp.lastlogin); m_pp.timePlayedMin = (TotalSecondsPlayed / 60); m_pp.RestTimer = rest_timer.GetRemainingTime() / 1000; - if(GetMercInfo().MercTimerRemaining > RuleI(Mercs, UpkeepIntervalMS)) - GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); - - if(GetMercTimer()->Enabled()) { - GetMercInfo().MercTimerRemaining = GetMercTimer()->GetRemainingTime(); - } - - if (GetMerc() && !dead) { - - } else { - memset(&m_mercinfo, 0, sizeof(struct MercInfo)); - } + /* Save Mercs */ + if (GetMercInfo().MercTimerRemaining > RuleI(Mercs, UpkeepIntervalMS)){ GetMercInfo().MercTimerRemaining = RuleI(Mercs, UpkeepIntervalMS); } + if(GetMercTimer()->Enabled()) { GetMercInfo().MercTimerRemaining = GetMercTimer()->GetRemainingTime(); } + if (GetMerc() && !dead) { } + else { memset(&m_mercinfo, 0, sizeof(struct MercInfo)); } m_pp.lastlogin = time(nullptr); if (pQueuedSaveWorkID) { @@ -591,19 +580,17 @@ bool Client::Save(uint8 iCommitNow) { } database.SavePetInfo(this); - if(tribute_timer.Enabled()) { - m_pp.tribute_time_remaining = tribute_timer.GetRemainingTime(); - } else { - m_pp.tribute_time_remaining = 0xFFFFFFFF; - m_pp.tribute_active = 0; - } + if(tribute_timer.Enabled()) { m_pp.tribute_time_remaining = tribute_timer.GetRemainingTime(); } + else { m_pp.tribute_time_remaining = 0xFFFFFFFF; m_pp.tribute_active = 0; } p_timers.Store(&database); -// printf("Dumping inventory on save:\n"); -// m_inv.dumpEntireInventory(); - + /* Save Character Task */ SaveTaskState(); + + /* Save Character Data */ + database.SaveCharacterData(this->CharacterID(), this->AccountID(), &m_pp); + if (iCommitNow <= 1) { char* query = 0; uint32_breakdown workpt; @@ -632,7 +619,7 @@ bool Client::Save(uint8 iCommitNow) { /* Mirror Character Data */ database.StoreCharacterLookup(this->CharacterID()); - + LogFile->write(EQEMuLog::Status, "Client::Save %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); return true; } @@ -2115,7 +2102,7 @@ bool Client::TakeMoneyFromPP(uint64 copper, bool updateclient) { m_pp.copper = copperpp; if(updateclient) SendMoneyUpdate(); - Save(); + SaveCurrency(); return true; } silver -= copper; @@ -2130,7 +2117,7 @@ bool Client::TakeMoneyFromPP(uint64 copper, bool updateclient) { m_pp.copper += (silver-(m_pp.silver*10)); if(updateclient) SendMoneyUpdate(); - Save(); + SaveCurrency(); return true; } @@ -2150,7 +2137,7 @@ bool Client::TakeMoneyFromPP(uint64 copper, bool updateclient) { m_pp.copper += coppertest; if(updateclient) SendMoneyUpdate(); - Save(); + SaveCurrency(); return true; } @@ -2168,7 +2155,7 @@ bool Client::TakeMoneyFromPP(uint64 copper, bool updateclient) { if(updateclient) SendMoneyUpdate(); RecalcWeight(); - Save(); + SaveCurrency(); return true; } } @@ -2234,7 +2221,7 @@ void Client::AddMoneyToPP(uint64 copper, bool updateclient){ RecalcWeight(); - Save(); + SaveCurrency(); LogFile->write(EQEMuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i", GetName(), m_pp.platinum, m_pp.gold, m_pp.silver, m_pp.copper); } @@ -2270,7 +2257,7 @@ void Client::AddMoneyToPP(uint32 copper, uint32 silver, uint32 gold, uint32 plat SendMoneyUpdate(); RecalcWeight(); - Save(); + SaveCurrency(); #if (EQDEBUG>=5) LogFile->write(EQEMuLog::Debug, "Client::AddMoneyToPP() %s should have: plat:%i gold:%i silver:%i copper:%i", @@ -2807,11 +2794,6 @@ void Client::SetMaterial(int16 in_slot, uint32 item_id) { m_pp.item_material[MaterialArms] = item->Material; else if (in_slot==MainWrist1) m_pp.item_material[MaterialWrist] = item->Material; - /* - // non-live behavior - else if (in_slot==SLOT_BRACER02) - m_pp.item_material[MaterialWrist] = item->Material; - */ else if (in_slot==MainHands) m_pp.item_material[MaterialHands] = item->Material; else if (in_slot==MainLegs) @@ -5734,7 +5716,7 @@ void Client::AddCrystals(uint32 Radiant, uint32 Ebon) m_pp.currentEbonCrystals += Ebon; m_pp.careerEbonCrystals += Ebon; - Save(); + SaveCurrency(); SendCrystalCounts(); } diff --git a/zone/client.h b/zone/client.h index d3aed5540..a490d73c4 100644 --- a/zone/client.h +++ b/zone/client.h @@ -313,6 +313,10 @@ public: bool Save(uint8 iCommitNow); // 0 = delayed, 1=async now, 2=sync now void SaveBackup(); + /* New PP Save Functions */ + bool SaveCurrency(){ return database.SaveCharacterCurrency(this->CharacterID(), &m_pp); } + bool SaveAA(); + inline bool ClientDataLoaded() const { return client_data_loaded; } inline bool Connected() const { return (client_state == CLIENT_CONNECTED); } inline bool InZone() const { return (client_state == CLIENT_CONNECTED || client_state == CLIENT_LINKDEAD); } diff --git a/zone/client_logs.cpp b/zone/client_logs.cpp index e51a51996..7ce3d5aab 100644 --- a/zone/client_logs.cpp +++ b/zone/client_logs.cpp @@ -33,14 +33,12 @@ void ClientLogs::subscribe(EQEMuLog::LogIDs id, Client *c) { if(c == nullptr) return; - //make sure they arnt allready subscribed. - std::vector::iterator cur,end; cur = entries[id].begin(); end = entries[id].end(); for(; cur != end; ++cur) { if(*cur == c) { - printf("%s was allready subscribed to %d\n", c->GetName(), id); + printf("%s was already subscribed to %d\n", c->GetName(), id); return; } } @@ -100,6 +98,7 @@ void ClientLogs::msg(EQEMuLog::LogIDs id, const char *buf) { for(; cur != end; ++cur) { if(!(*cur)->InZone()) continue; + (*cur)->Message(CLIENT_LOG_CHANNEL, buf); } } diff --git a/zone/client_packet.cpp b/zone/client_packet.cpp index 91d99490f..abf044caa 100644 --- a/zone/client_packet.cpp +++ b/zone/client_packet.cpp @@ -8698,6 +8698,8 @@ void Client::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { break; } case DBA_b1_Entity_Client_Save: { + clock_t t = std::clock(); /* Function timer start */ + char errbuf[MYSQL_ERRMSG_SIZE]; uint32 affected_rows = 0; DBAsyncQuery* dbaq = dbaw->PopAnswer(); @@ -8713,6 +8715,8 @@ void Client::DBAWComplete(uint8 workpt_b1, DBAsyncWork* dbaw) { Message(13, "errbuf: %s", errbuf); } pQueuedSaveWorkID = 0; + + LogFile->write(EQEMuLog::Status, "Client::DBAWComplete Save Character Async done... Took %f seconds", ((float)(std::clock() - t)) / CLOCKS_PER_SEC); break; } default: { @@ -8761,12 +8765,17 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { } } - // This should be a part of the PlayerProfile BLOB, but we don't want to modify that - // The player inspect message is retrieved from the db on load, then saved as new updates come in..no mods to Client::Save() - database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); + /* Load Character Currency into PP */ + database.LoadCharacterCurrency(CharacterID(), &m_pp); + /* Load Character Data from DB into PP */ + database.LoadCharacterData(CharacterID(), &m_pp); + /* Move to another method when can, this is pointless... */ + database.GetPlayerInspectMessage(m_pp.name, &m_inspect_message); + /* Load Character Currency*/ + database.LoadCharacterCurrency(CharacterID(), &m_pp); conn_state = PlayerProfileLoaded; - + /* Set Current zone */ m_pp.zone_id = zone->GetZoneID(); m_pp.zoneInstance = zone->GetInstanceID(); @@ -8820,7 +8829,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { base_race = m_pp.race; gender = m_pp.gender; base_gender = m_pp.gender; - deity = m_pp.deity;//FYI: DEITY_AGNOSTIC = 396; still valid? + deity = m_pp.deity; //FYI: DEITY_AGNOSTIC = 396; still valid? haircolor = m_pp.haircolor; beardcolor = m_pp.beardcolor; eyecolor1 = m_pp.eyecolor1; @@ -8833,8 +8842,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { drakkin_details = m_pp.drakkin_details; //if we zone in with invalid Z, fix it. - if (zone->zonemap != nullptr) { - + if (zone->zonemap != nullptr) { Map::Vertex me; me.x = GetX(); me.y = GetY(); @@ -8871,19 +8879,13 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { if (m_pp.gm && admin < minStatusToBeGM) m_pp.gm = 0; - if (m_pp.platinum < 0 || m_pp.gold < 0 || m_pp.silver < 0 || m_pp.copper < 0 ) - { - m_pp.platinum = 0; - m_pp.gold = 0; - m_pp.silver = 0; - m_pp.copper = 0; - } + + /* Load Guild */ if (!IsInAGuild()) { m_pp.guild_id = GUILD_NONE; } - else - { + else { m_pp.guild_id = GuildID(); if(zone->GetZoneID() == RuleI(World, GuildBankZoneID)) @@ -8895,120 +8897,89 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { switch (race) { case OGRE: - size = 9; - break; + size = 9; break; case TROLL: - size = 8; - break; - case VAHSHIR: - case BARBARIAN: - size = 7; - break; - case HUMAN: - case HIGH_ELF: - case ERUDITE: - case IKSAR: - case DRAKKIN: - size = 6; - break; + size = 8; break; + case VAHSHIR: case BARBARIAN: + size = 7; break; + case HUMAN: case HIGH_ELF: case ERUDITE: case IKSAR: case DRAKKIN: + size = 6; break; case HALF_ELF: - size = 5.5; - break; - case WOOD_ELF: - case DARK_ELF: - case FROGLOK: - size = 5; - break; + size = 5.5; break; + case WOOD_ELF: case DARK_ELF: case FROGLOK: + size = 5; break; case DWARF: - size = 4; - break; + size = 4; break; case HALFLING: - size = 3.5; - break; + size = 3.5; break; case GNOME: - size = 3; - break; + size = 3; break; default: size = 0; } - //validate skills - //im not sure I follow this logic... commenting for now... - /* - if(Admin() < minStatusToHaveInvalidSkills) { - SkillType sk; - for (sk = _1H_BLUNT; sk <= HIGHEST_SKILL; sk = (SkillType)(sk+1)) { - //int cap = GetSkillCap(sk-1); - int cap = MaxSkill(sk-1, GetClass(), GetLevel()); - if (cap >= 254) - m_pp.skills[sk] = cap; - } - } - */ - - //validate adventure points, this cap is arbitrary at 2,000,000,000 - if(m_pp.ldon_points_guk < 0) - m_pp.ldon_points_guk = 0; - if(m_pp.ldon_points_guk > 0x77359400) - m_pp.ldon_points_guk = 0x77359400; - if(m_pp.ldon_points_mir < 0) - m_pp.ldon_points_mir = 0; - if(m_pp.ldon_points_mir > 0x77359400) - m_pp.ldon_points_mir = 0x77359400; - if(m_pp.ldon_points_mmc < 0) - m_pp.ldon_points_mmc = 0; - if(m_pp.ldon_points_mmc > 0x77359400) - m_pp.ldon_points_mmc = 0x77359400; - if(m_pp.ldon_points_ruj < 0) - m_pp.ldon_points_ruj = 0; - if(m_pp.ldon_points_ruj > 0x77359400) - m_pp.ldon_points_ruj = 0x77359400; - if(m_pp.ldon_points_tak < 0) - m_pp.ldon_points_tak = 0; - if(m_pp.ldon_points_tak > 0x77359400) - m_pp.ldon_points_tak = 0x77359400; - if(m_pp.ldon_points_available < 0) - m_pp.ldon_points_available = 0; - if(m_pp.ldon_points_available > 0x77359400) - m_pp.ldon_points_available = 0x77359400; - + /* Check for Invalid points */ + if (m_pp.ldon_points_guk < 0 || m_pp.ldon_points_guk > 2000000000){ m_pp.ldon_points_guk = 0; } + if (m_pp.ldon_points_mir < 0 || m_pp.ldon_points_mir > 2000000000){ m_pp.ldon_points_mir = 0; } + if (m_pp.ldon_points_mmc < 0 || m_pp.ldon_points_mmc > 2000000000){ m_pp.ldon_points_mmc = 0; } + if (m_pp.ldon_points_ruj < 0 || m_pp.ldon_points_ruj > 2000000000){ m_pp.ldon_points_ruj = 0; } + if (m_pp.ldon_points_tak < 0 || m_pp.ldon_points_tak > 2000000000){ m_pp.ldon_points_tak = 0; } + if (m_pp.ldon_points_available < 0 || m_pp.ldon_points_available > 2000000000){ m_pp.ldon_points_available = 0; } + if(GetSkill(SkillSwimming) < 100) - SetSkill(SkillSwimming,100); + SetSkill(SkillSwimming, 100); - //pull AAs from the PP - for(uint32 a=0; a < MAX_PP_AA_ARRAY; a++){ - //set up our AA pointer + + + /* Load Character AA's */ + //database.LoadCharacterAA(this->CharacterID(), &m_pp, &aa, &aa_points); + + /* Initialize AA's */ + for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ aa[a] = &m_pp.aa_array[a]; - - + } + std::string query = StringFormat( + "SELECT " + "slot, " + "aa_id, " + "aa_value " + "FROM " + "`character_alternate_abilities` " + "WHERE `id` = %i ORDER BY `slot`", this->CharacterID()); + auto results = database.QueryDatabase(query); int si = 0; + for (auto row = results.begin(); row != results.end(); ++row) { + si = atoi(row[0]); + m_pp.aa_array[si].AA = atoi(row[1]); + m_pp.aa_array[si].value = atoi(row[1]); + aa[si]->AA = atoi(row[1]); + aa[si]->value = atoi(row[2]); + } + for (uint32 a = 0; a < MAX_PP_AA_ARRAY; a++){ uint32 id = aa[a]->AA; //watch for invalid AA IDs - if(id == aaNone) + if (id == aaNone) continue; - if(id >= aaHighestID) { + if (id >= aaHighestID) { + aa[a]->AA = aaNone; + aa[a]->value = 0; + continue; + } + if (aa[a]->value == 0) { + aa[a]->AA = aaNone; + continue; + } + if (aa[a]->value > HIGHEST_AA_VALUE) { aa[a]->AA = aaNone; aa[a]->value = 0; continue; } - //watch for invalid AA values - if(aa[a]->value == 0) { - aa[a]->AA = aaNone; - continue; - } - if(aa[a]->value > HIGHEST_AA_VALUE) { - aa[a]->AA = aaNone; - aa[a]->value = 0; - continue; - } - - if(aa[a]->value > 1) //hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) - aa_points[(id - aa[a]->value +1)] = aa[a]->value; + if (aa[a]->value > 1) /* hack in some stuff for sony's new AA method (where each level of each aa.has a seperate ID) */ + aa_points[(id - aa[a]->value + 1)] = aa[a]->value; else aa_points[id] = aa[a]->value; } - if(SPDAT_RECORDS > 0) { for(uint32 z=0;z 0){ @@ -9128,6 +9101,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { m_pp.z = zone->newzone_data.safe_z; } + /* Get Expansions from variables table and ship via PP */ char val[20] = {0}; if (database.GetVariable("Expansions", val, 20)) m_pp.expansions = atoi(val); @@ -9143,14 +9117,11 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { if(IsValidSpell(m_pp.mem_spells[i])) m_pp.spellSlotRefresh[i] = p_timers.GetRemainingTime(pTimerSpellStart + m_pp.mem_spells[i]) * 1000; - if(m_pp.class_==SHADOWKNIGHT || m_pp.class_==PALADIN) - { + /* Ability slot refresh send SK/PAL */ + if(m_pp.class_==SHADOWKNIGHT || m_pp.class_==PALADIN) { uint32 abilitynum=0; - if(m_pp.class_==SHADOWKNIGHT) - abilitynum = pTimerHarmTouch; - else - abilitynum = pTimerLayHands; - + if (m_pp.class_ == SHADOWKNIGHT){ abilitynum = pTimerHarmTouch; } + else{ abilitynum = pTimerLayHands; } uint32 remaining = p_timers.GetRemainingTime(abilitynum); if(remaining > 0 && remaining < 15300) @@ -9174,16 +9145,16 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { m_pp.timeentitledonaccount = database.GetTotalTimeEntitledOnAccount(AccountID()) / 1440; - // Reset rest timer if the durations have been lowered in the database + /* Reset rest timer if the durations have been lowered in the database */ if ((m_pp.RestTimer > RuleI(Character, RestRegenTimeToActivate)) && (m_pp.RestTimer > RuleI(Character, RestRegenRaidTimeToActivate))) m_pp.RestTimer = 0; - //This checksum should disappear once dynamic structs are in... each struct strategy will do it + /* This checksum should disappear once dynamic structs are in... each struct strategy will do it */ CRC32::SetEQChecksum((unsigned char*)&m_pp, sizeof(PlayerProfile_Struct)-4); outapp = new EQApplicationPacket(OP_PlayerProfile,sizeof(PlayerProfile_Struct)); - // The entityid field in the Player Profile is used by the Client in relation to Group Leadership AA + /* The entityid field in the Player Profile is used by the Client in relation to Group Leadership AA */ m_pp.entityid = GetID(); memcpy(outapp->pBuffer,&m_pp,outapp->size); outapp->priority = 6; @@ -9193,9 +9164,11 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { rest_timer.Start(m_pp.RestTimer * 1000); database.LoadPetInfo(this); - //this was moved before the spawn packets are sent - //in hopes that it adds more consistency... - //Remake pet + /* + This was moved before the spawn packets are sent + in hopes that it adds more consistency... + Remake pet + */ if (m_petinfo.SpellID > 1 && !GetPet() && m_petinfo.SpellID <= SPDAT_RECORDS) { MakePoweredPet(m_petinfo.SpellID, spells[m_petinfo.SpellID].teleport_zone, m_petinfo.petpower, m_petinfo.Name, m_petinfo.size); @@ -9208,7 +9181,7 @@ bool Client::FinishConnState2(DBAsyncWork* dbaw) { } m_petinfo.SpellID = 0; } - // Moved here so it's after where we load the pet data. + /* Moved here so it's after where we load the pet data. */ if(!GetAA(aaPersistentMinion)) memset(&m_suspendedminion, 0, sizeof(PetInfo)); @@ -12894,13 +12867,13 @@ void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app) { SummonItem(RuleI(Zone, EbonCrystalItemID), GetEbonCrystals()); m_pp.currentEbonCrystals = 0; m_pp.careerEbonCrystals = 0; - Save(); + SaveCurrency(); SendCrystalCounts(); } else { SummonItem(RuleI(Zone, EbonCrystalItemID), cr->amount); m_pp.currentEbonCrystals -= cr->amount; m_pp.careerEbonCrystals -= cr->amount; - Save(); + SaveCurrency(); SendCrystalCounts(); } } else if(cr->type == 4) { @@ -12908,13 +12881,13 @@ void Client::Handle_OP_CrystalCreate(const EQApplicationPacket *app) { SummonItem(RuleI(Zone, RadiantCrystalItemID), GetRadiantCrystals()); m_pp.currentRadCrystals = 0; m_pp.careerRadCrystals = 0; - Save(); + SaveCurrency(); SendCrystalCounts(); } else { SummonItem(RuleI(Zone, RadiantCrystalItemID), cr->amount); m_pp.currentRadCrystals -= cr->amount; m_pp.careerRadCrystals -= cr->amount; - Save(); + SaveCurrency(); SendCrystalCounts(); } } diff --git a/zone/client_process.cpp b/zone/client_process.cpp index e39cef0bd..fd8cb3740 100644 --- a/zone/client_process.cpp +++ b/zone/client_process.cpp @@ -1582,7 +1582,7 @@ void Client::OPMoveCoin(const EQApplicationPacket* app) safe_delete(outapp); } - Save(); + SaveCurrency(); } void Client::OPGMTraining(const EQApplicationPacket *app) diff --git a/zone/command.cpp b/zone/command.cpp index b14a173bc..011cb0f09 100644 --- a/zone/command.cpp +++ b/zone/command.cpp @@ -6273,13 +6273,13 @@ void command_setcrystals(Client *c, const Seperator *sep) { t->SetRadiantCrystals(atoi(sep->arg[2])); t->SendCrystalCounts(); - t->Save(); + t->SaveCurrency(); } else if(!strcasecmp(sep->arg[1], "ebon")) { t->SetEbonCrystals(atoi(sep->arg[2])); t->SendCrystalCounts(); - t->Save(); + t->SaveCurrency(); } else { diff --git a/zone/corpse.cpp b/zone/corpse.cpp index aa7841a64..083dc0b12 100644 --- a/zone/corpse.cpp +++ b/zone/corpse.cpp @@ -971,8 +971,7 @@ void Corpse::MakeLootRequestPackets(Client* client, const EQApplicationPacket* a } RemoveCash(); - Save(); - client->Save(); + Save(); } outapp->priority = 6; diff --git a/zone/zonedb.cpp b/zone/zonedb.cpp index 725f6395a..e7bad016c 100644 --- a/zone/zonedb.cpp +++ b/zone/zonedb.cpp @@ -5,6 +5,7 @@ #include "../common/extprofile.h" #include "../common/guilds.h" #include "../common/rulesys.h" +#include "../common/rdtsc.h" #include "zone.h" #include "client.h" #include "merc.h" @@ -13,6 +14,7 @@ #include #include #include +#include extern Zone* zone; @@ -893,12 +895,575 @@ bool ZoneDatabase::GetCharacterInfoForLogin(const char* name, uint32* character_ #define StructDist(in, f1, f2) (uint32(&in->f2)-uint32(&in->f1)) + +bool ZoneDatabase::LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "`name`, " + "last_name, " + "gender, " + "race, " + "class, " + "`level`, " + "deity, " + "birthday, " + "last_login, " + "time_played, " + "pvp_status, " + "level2, " + "anon, " + "gm, " + "intoxication, " + "hair_color, " + "beard_color, " + "eye_color_1, " + "eye_color_2, " + "hair_style, " + "beard, " + "ability_time_seconds, " + "ability_number, " + "ability_time_minutes, " + "ability_time_hours, " + "title, " + "suffix, " + "exp, " + "points, " + "mana, " + "cur_hp, " + "str, " + "sta, " + "cha, " + "dex, " + "`int`, " + "agi, " + "wis, " + "face, " + "y, " + "x, " + "z, " + "heading, " + "pvp2, " + "pvp_type, " + "autosplit_enabled, " + "zone_change_count, " + "drakkin_heritage, " + "drakkin_tattoo, " + "drakkin_details, " + "toxicity, " + "hunger_level, " + "thirst_level, " + "ability_up, " + "zone_id, " + "zone_instance, " + "leadership_exp_on, " + "ldon_points_guk, " + "ldon_points_mir, " + "ldon_points_mmc, " + "ldon_points_ruj, " + "ldon_points_tak, " + "ldon_points_available, " + "tribute_time_remaining, " + "show_helm, " + "career_tribute_points, " + "tribute_points, " + "tribute_active, " + "endurance, " + "group_leadership_exp, " + "raid_leadership_exp, " + "group_leadership_points, " + "raid_leadership_points, " + "air_remaining, " + "pvp_kills, " + "pvp_deaths, " + "pvp_current_points, " + "pvp_career_points, " + "pvp_best_kill_streak, " + "pvp_worst_death_streak, " + "pvp_current_kill_streak, " + "aa_points_spent, " + "aa_exp, " + "aa_points, " + "group_auto_consent, " + "raid_auto_consent, " + "guild_auto_consent, " + "RestTimer " + "FROM " + "character_data " + "WHERE `id` = %i ", character_id); + auto results = database.QueryDatabase(query); int r = 0; + for (auto row = results.begin(); row != results.end(); ++row) { + strcpy(pp->name, row[r]); r++; + strcpy(pp->last_name, row[r]); r++; + pp->gender = atoi(row[r]); r++; + pp->race = atoi(row[r]); r++; + pp->class_ = atoi(row[r]); r++; + pp->level = atoi(row[r]); r++; + pp->deity = atoi(row[r]); r++; + pp->birthday = atoi(row[r]); r++; + pp->lastlogin = atoi(row[r]); r++; + pp->timePlayedMin = atoi(row[r]); r++; + pp->pvp = atoi(row[r]); r++; + pp->level2 = atoi(row[r]); r++; + pp->anon = atoi(row[r]); r++; + pp->gm = atoi(row[r]); r++; + pp->intoxication = atoi(row[r]); r++; + pp->haircolor = atoi(row[r]); r++; + pp->beardcolor = atoi(row[r]); r++; + pp->eyecolor1 = atoi(row[r]); r++; + pp->eyecolor2 = atoi(row[r]); r++; + pp->hairstyle = atoi(row[r]); r++; + pp->beard = atoi(row[r]); r++; + pp->ability_time_seconds = atoi(row[r]); r++; + pp->ability_number = atoi(row[r]); r++; + pp->ability_time_minutes = atoi(row[r]); r++; + pp->ability_time_hours = atoi(row[r]); r++; + strcpy(pp->title, row[r]); r++; + strcpy(pp->suffix, row[r]); r++; + pp->exp = atoi(row[r]); r++; + pp->points = atoi(row[r]); r++; + pp->mana = atoi(row[r]); r++; + pp->cur_hp = atoi(row[r]); r++; + pp->STR = atoi(row[r]); r++; + pp->STA = atoi(row[r]); r++; + pp->CHA = atoi(row[r]); r++; + pp->DEX = atoi(row[r]); r++; + pp->INT = atoi(row[r]); r++; + pp->AGI = atoi(row[r]); r++; + pp->WIS = atoi(row[r]); r++; + pp->face = atoi(row[r]); r++; + pp->y = atof(row[r]); r++; + pp->x = atof(row[r]); r++; + pp->z = atof(row[r]); r++; + pp->heading = atof(row[r]); r++; + pp->pvp2 = atoi(row[r]); r++; + pp->pvptype = atoi(row[r]); r++; + pp->autosplit = atoi(row[r]); r++; + pp->zone_change_count = atoi(row[r]); r++; + pp->drakkin_heritage = atoi(row[r]); r++; + pp->drakkin_tattoo = atoi(row[r]); r++; + pp->drakkin_details = atoi(row[r]); r++; + pp->toxicity = atoi(row[r]); r++; + pp->hunger_level = atoi(row[r]); r++; + pp->thirst_level = atoi(row[r]); r++; + pp->ability_up = atoi(row[r]); r++; + pp->zone_id = atoi(row[r]); r++; + pp->zoneInstance = atoi(row[r]); r++; + pp->leadAAActive = atoi(row[r]); r++; + pp->ldon_points_guk = atoi(row[r]); r++; + pp->ldon_points_mir = atoi(row[r]); r++; + pp->ldon_points_mmc = atoi(row[r]); r++; + pp->ldon_points_ruj = atoi(row[r]); r++; + pp->ldon_points_tak = atoi(row[r]); r++; + pp->ldon_points_available = atoi(row[r]); r++; + pp->tribute_time_remaining = atoi(row[r]); r++; + pp->showhelm = atoi(row[r]); r++; + pp->career_tribute_points = atoi(row[r]); r++; + pp->tribute_points = atoi(row[r]); r++; + pp->tribute_active = atoi(row[r]); r++; + pp->endurance = atoi(row[r]); r++; + pp->group_leadership_exp = atoi(row[r]); r++; + pp->raid_leadership_exp = atoi(row[r]); r++; + pp->group_leadership_points = atoi(row[r]); r++; + pp->raid_leadership_points = atoi(row[r]); r++; + pp->air_remaining = atoi(row[r]); r++; + pp->PVPKills = atoi(row[r]); r++; + pp->PVPDeaths = atoi(row[r]); r++; + pp->PVPCurrentPoints = atoi(row[r]); r++; + pp->PVPCareerPoints = atoi(row[r]); r++; + pp->PVPBestKillStreak = atoi(row[r]); r++; + pp->PVPWorstDeathStreak = atoi(row[r]); r++; + pp->PVPCurrentKillStreak = atoi(row[r]); r++; + pp->aapoints_spent = atoi(row[r]); r++; + pp->expAA = atoi(row[r]); r++; + pp->aapoints = atoi(row[r]); r++; + pp->groupAutoconsent = atoi(row[r]); r++; + pp->raidAutoconsent = atoi(row[r]); r++; + pp->guildAutoconsent = atoi(row[r]); r++; + pp->RestTimer = atoi(row[r]); r++; + LogFile->write(EQEMuLog::Status, "Loading Character Data for character ID: %i, done", character_id); + } + return true; +} + +bool ZoneDatabase::LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp){ + std::string query = StringFormat( + "SELECT " + "platinum, " + "gold, " + "silver, " + "copper, " + "platinum_bank, " + "gold_bank, " + "silver_bank, " + "copper_bank, " + "platinum_cursor, " + "gold_cursor, " + "silver_cursor, " + "copper_cursor, " + "radiant_crystals, " + "career_radiant_crystals," + "ebon_crystals, " + "career_ebon_crystals " + "FROM " + "character_currency " + "WHERE `id` = %i ", character_id); + auto results = database.QueryDatabase(query); + for (auto row = results.begin(); row != results.end(); ++row) { + pp->platinum = atoi(row[0]); + pp->gold = atoi(row[1]); + pp->silver = atoi(row[2]); + pp->copper = atoi(row[3]); + pp->platinum_bank = atoi(row[4]); + pp->gold_bank = atoi(row[5]); + pp->silver_bank = atoi(row[6]); + pp->copper_bank = atoi(row[7]); + pp->platinum_cursor = atoi(row[8]); + pp->gold_cursor = atoi(row[9]); + pp->silver_cursor = atoi(row[10]); + pp->copper_cursor = atoi(row[11]); + pp->currentRadCrystals = atoi(row[12]); + pp->careerRadCrystals = atoi(row[13]); + pp->currentEbonCrystals = atoi(row[14]); + pp->careerEbonCrystals = atoi(row[15]); + LogFile->write(EQEMuLog::Status, "Loading Currency for character ID: %i, done", character_id); + } + return true; +} + +bool ZoneDatabase::SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp){ + clock_t t = std::clock(); /* Function timer start */ + std::string query = StringFormat( + "REPLACE INTO `character_data` (" + " id, " + " account_id, " + " `name`, " + " last_name, " + " gender, " + " race, " + " class, " + " `level`, " + " deity, " + " birthday, " + " last_login, " + " time_played, " + " pvp_status, " + " level2, " + " anon, " + " gm, " + " intoxication, " + " hair_color, " + " beard_color, " + " eye_color_1, " + " eye_color_2, " + " hair_style, " + " beard, " + " ability_time_seconds, " + " ability_number, " + " ability_time_minutes, " + " ability_time_hours, " + " title, " + " suffix, " + " exp, " + " points, " + " mana, " + " cur_hp, " + " str, " + " sta, " + " cha, " + " dex, " + " `int`, " + " agi, " + " wis, " + " face, " + " y, " + " x, " + " z, " + " heading, " + " pvp2, " + " pvp_type, " + " autosplit_enabled, " + " zone_change_count, " + " drakkin_heritage, " + " drakkin_tattoo, " + " drakkin_details, " + " toxicity, " + " hunger_level, " + " thirst_level, " + " ability_up, " + " zone_id, " + " zone_instance, " + " leadership_exp_on, " + " ldon_points_guk, " + " ldon_points_mir, " + " ldon_points_mmc, " + " ldon_points_ruj, " + " ldon_points_tak, " + " ldon_points_available, " + " tribute_time_remaining, " + " show_helm, " + " career_tribute_points, " + " tribute_points, " + " tribute_active, " + " endurance, " + " group_leadership_exp, " + " raid_leadership_exp, " + " group_leadership_points, " + " raid_leadership_points, " + " air_remaining, " + " pvp_kills, " + " pvp_deaths, " + " pvp_current_points, " + " pvp_career_points, " + " pvp_best_kill_streak, " + " pvp_worst_death_streak, " + " pvp_current_kill_streak, " + " aa_points_spent, " + " aa_exp, " + " aa_points, " + " group_auto_consent, " + " raid_auto_consent, " + " guild_auto_consent, " + " RestTimer) " + "VALUES (" + "%i," // id " id, " + "%i," // account_id " account_id, " + "'%s'," // `name` pp->name, " `name`, " + "'%s'," // last_name pp->last_name, " last_name, " + "%i," // gender pp->gender, " gender, " + "%i," // race pp->race, " race, " + "%i," // class pp->class_, " class, " + "%i," // `level` pp->level, " `level`, " + "%i," // deity pp->deity, " deity, " + "%i," // birthday pp->birthday, " birthday, " + "%i," // last_login pp->lastlogin, " last_login, " + "%i," // time_played pp->timePlayedMin, " time_played, " + "%i," // pvp_status pp->pvp, " pvp_status, " + "%i," // level2 pp->level2, " level2, " + "%i," // anon pp->anon, " anon, " + "%i," // gm pp->gm, " gm, " + "%i," // intoxication pp->intoxication, " intoxication, " + "%i," // hair_color pp->haircolor, " hair_color, " + "%i," // beard_color pp->beardcolor, " beard_color, " + "%i," // eye_color_1 pp->eyecolor1, " eye_color_1, " + "%i," // eye_color_2 pp->eyecolor2, " eye_color_2, " + "%i," // hair_style pp->hairstyle, " hair_style, " + "%i," // beard pp->beard, " beard, " + "%i," // ability_time_seconds pp->ability_time_seconds, " ability_time_seconds, " + "%i," // ability_number pp->ability_number, " ability_number, " + "%i," // ability_time_minutes pp->ability_time_minutes, " ability_time_minutes, " + "%i," // ability_time_hours pp->ability_time_hours, " ability_time_hours, " + "'%s'," // title pp->title, " title, " " + "'%s'," // suffix pp->suffix, " suffix, " + "%i," // exp pp->exp, " exp, " + "%i," // points pp->points, " points, " + "%i," // mana pp->mana, " mana, " + "%i," // cur_hp pp->cur_hp, " cur_hp, " + "%i," // str pp->STR, " str, " + "%i," // sta pp->STA, " sta, " + "%i," // cha pp->CHA, " cha, " + "%i," // dex pp->DEX, " dex, " + "%i," // `int` pp->INT, " `int`, " + "%i," // agi pp->AGI, " agi, " + "%i," // wis pp->WIS, " wis, " + "%i," // face pp->face, " face, " + "%f," // y pp->y, " y, " + "%f," // x pp->x, " x, " + "%f," // z pp->z, " z, " + "%f," // heading pp->heading, " heading, " + "%i," // pvp2 pp->pvp2, " pvp2, " + "%i," // pvp_type pp->pvptype, " pvp_type, " + "%i," // autosplit_enabled pp->autosplit, " autosplit_enabled, " + "%i," // zone_change_count pp->zone_change_count, " zone_change_count, " + "%i," // drakkin_heritage pp->drakkin_heritage, " drakkin_heritage, " + "%i," // drakkin_tattoo pp->drakkin_tattoo, " drakkin_tattoo, " + "%i," // drakkin_details pp->drakkin_details, " drakkin_details, " + "%i," // toxicity pp->toxicity, " toxicity, " + "%i," // hunger_level pp->hunger_level, " hunger_level, " + "%i," // thirst_level pp->thirst_level, " thirst_level, " + "%i," // ability_up pp->ability_up, " ability_up, " + "%i," // zone_id pp->zone_id, " zone_id, " + "%i," // zone_instance pp->zoneInstance, " zone_instance, " + "%i," // leadership_exp_on pp->leadAAActive, " leadership_exp_on, " + "%i," // ldon_points_guk pp->ldon_points_guk, " ldon_points_guk, " + "%i," // ldon_points_mir pp->ldon_points_mir, " ldon_points_mir, " + "%i," // ldon_points_mmc pp->ldon_points_mmc, " ldon_points_mmc, " + "%i," // ldon_points_ruj pp->ldon_points_ruj, " ldon_points_ruj, " + "%i," // ldon_points_tak pp->ldon_points_tak, " ldon_points_tak, " + "%i," // ldon_points_available pp->ldon_points_available, " ldon_points_available, " + "%i," // tribute_time_remaining pp->tribute_time_remaining, " tribute_time_remaining, " + "%i," // show_helm pp->showhelm, " show_helm, " + "%i," // career_tribute_points pp->career_tribute_points, " career_tribute_points, " + "%i," // tribute_points pp->tribute_points, " tribute_points, " + "%i," // tribute_active pp->tribute_active, " tribute_active, " + "%i," // endurance pp->endurance, " endurance, " + "%i," // group_leadership_exp pp->group_leadership_exp, " group_leadership_exp, " + "%i," // raid_leadership_exp pp->raid_leadership_exp, " raid_leadership_exp, " + "%i," // group_leadership_points pp->group_leadership_points, " group_leadership_points, " + "%i," // raid_leadership_points pp->raid_leadership_points, " raid_leadership_points, " + "%i," // air_remaining pp->air_remaining, " air_remaining, " + "%i," // pvp_kills pp->PVPKills, " pvp_kills, " + "%i," // pvp_deaths pp->PVPDeaths, " pvp_deaths, " + "%i," // pvp_current_points pp->PVPCurrentPoints, " pvp_current_points, " + "%i," // pvp_career_points pp->PVPCareerPoints, " pvp_career_points, " + "%i," // pvp_best_kill_streak pp->PVPBestKillStreak, " pvp_best_kill_streak, " + "%i," // pvp_worst_death_streak pp->PVPWorstDeathStreak, " pvp_worst_death_streak, " + "%i," // pvp_current_kill_streak pp->PVPCurrentKillStreak, " pvp_current_kill_streak, " + "%i," // aa_points_spent pp->aapoints_spent, " aa_points_spent, " + "%i," // aa_exp pp->expAA, " aa_exp, " + "%i," // aa_points pp->aapoints, " aa_points, " + "%i," // group_auto_consent pp->groupAutoconsent, " group_auto_consent, " + "%i," // raid_auto_consent pp->raidAutoconsent, " raid_auto_consent, " + "%i," // guild_auto_consent pp->guildAutoconsent, " guild_auto_consent, " + "%i" // RestTimer pp->RestTimer, " RestTimer) " + ")", + character_id, + account_id, + pp->name, + pp->last_name, + pp->gender, + pp->race, + pp->class_, + pp->level, + pp->deity, + pp->birthday, + pp->lastlogin, + pp->timePlayedMin, + pp->pvp, + pp->level2, + pp->anon, + pp->gm, + pp->intoxication, + pp->haircolor, + pp->beardcolor, + pp->eyecolor1, + pp->eyecolor2, + pp->hairstyle, + pp->beard, + pp->ability_time_seconds, + pp->ability_number, + pp->ability_time_minutes, + pp->ability_time_hours, + pp->title, + pp->suffix, + pp->exp, + pp->points, + pp->mana, + pp->cur_hp, + pp->STR, + pp->STA, + pp->CHA, + pp->DEX, + pp->INT, + pp->AGI, + pp->WIS, + pp->face, + pp->y, + pp->x, + pp->z, + pp->heading, + pp->pvp2, + pp->pvptype, + pp->autosplit, + pp->zone_change_count, + pp->drakkin_heritage, + pp->drakkin_tattoo, + pp->drakkin_details, + pp->toxicity, + pp->hunger_level, + pp->thirst_level, + pp->ability_up, + pp->zone_id, + pp->zoneInstance, + pp->leadAAActive, + pp->ldon_points_guk, + pp->ldon_points_mir, + pp->ldon_points_mmc, + pp->ldon_points_ruj, + pp->ldon_points_tak, + pp->ldon_points_available, + pp->tribute_time_remaining, + pp->showhelm, + pp->career_tribute_points, + pp->tribute_points, + pp->tribute_active, + pp->endurance, + pp->group_leadership_exp, + pp->raid_leadership_exp, + pp->group_leadership_points, + pp->raid_leadership_points, + pp->air_remaining, + pp->PVPKills, + pp->PVPDeaths, + pp->PVPCurrentPoints, + pp->PVPCareerPoints, + pp->PVPBestKillStreak, + pp->PVPWorstDeathStreak, + pp->PVPCurrentKillStreak, + pp->aapoints_spent, + pp->expAA, + pp->aapoints, + pp->groupAutoconsent, + pp->raidAutoconsent, + pp->guildAutoconsent, + pp->RestTimer + ); + auto results = database.QueryDatabase(query); + LogFile->write(EQEMuLog::Status, "ZoneDatabase::SaveCharacterData %i, done... Took %f seconds", character_id, ((float)(std::clock() - t)) / CLOCKS_PER_SEC); + return true; +} + +bool ZoneDatabase::SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp){ + if (pp->copper < 0) { pp->copper = 0; } + if (pp->silver < 0) { pp->silver = 0; } + if (pp->gold < 0) { pp->gold = 0; } + if (pp->platinum < 0) { pp->platinum = 0; } + if (pp->copper_bank < 0) { pp->copper_bank = 0; } + if (pp->silver_bank < 0) { pp->silver_bank = 0; } + if (pp->gold_bank < 0) { pp->gold_bank = 0; } + if (pp->platinum_bank < 0) { pp->platinum_bank = 0; } + std::string query = StringFormat( + "REPLACE INTO `character_currency` (id, platinum, gold, silver, copper," + "platinum_bank, gold_bank, silver_bank, copper_bank," + "platinum_cursor, gold_cursor, silver_cursor, copper_cursor, " + "radiant_crystals, career_radiant_crystals, ebon_crystals, career_ebon_crystals)" + "VALUES (%u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u, %u)", + character_id, + pp->platinum, + pp->gold, + pp->silver, + pp->copper, + pp->platinum_bank, + pp->gold_bank, + pp->silver_bank, + pp->copper_bank, + pp->platinum_cursor, + pp->gold_cursor, + pp->silver_cursor, + pp->copper_cursor, + pp->currentRadCrystals, + pp->careerRadCrystals, + pp->currentEbonCrystals, + pp->careerEbonCrystals); + auto results = database.QueryDatabase(query); + LogFile->write(EQEMuLog::Status, "Saving Currency for character ID: %i, done", character_id); + return true; +} + +bool ZoneDatabase::SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level){ + std::string rquery = StringFormat("REPLACE INTO `character_alternate_abilities` (id, aa_id, aa_value)" + " VALUES (%u, %u, %u)", + character_id, aa_id, current_level); + auto results = QueryDatabase(rquery); + LogFile->write(EQEMuLog::Status, "Saving AA for character ID: %i, aa_id: %u current_level: %i", character_id, aa_id, current_level); + return true; +} + // Process results of GetCharacterInfoForLogin() // Query this processes: SELECT id,profile,zonename,x,y,z,guild,guildrank,extprofile,class,level FROM character_ WHERE id=%i bool ZoneDatabase::GetCharacterInfoForLogin_result(MYSQL_RES* result, uint32* character_id, char* current_zone, PlayerProfile_Struct* pp, Inventory* inv, ExtendedProfile_Struct *ext, uint32* pplen, uint32* guilddbid, uint8* guildrank, - uint8 *class_, uint8 *level, bool *LFP, bool *LFG, uint8 *NumXTargets, uint8* firstlogon) { + uint8 *class_, uint8 *level, bool *LFP, bool *LFG, uint8 *NumXTargets, uint8* firstlogon) { MYSQL_ROW row; unsigned long* lengths; @@ -908,7 +1473,7 @@ bool ZoneDatabase::GetCharacterInfoForLogin_result(MYSQL_RES* result, lengths = mysql_fetch_lengths(result); if (pp && pplen) { if (lengths[1] == sizeof(PlayerProfile_Struct)) { - memcpy(pp, row[1], sizeof(PlayerProfile_Struct)); + // memcpy(pp, row[1], sizeof(PlayerProfile_Struct)); } else { LogFile->write(EQEMuLog::Error, "Player profile length mismatch in GetCharacterInfo Expected: %i, Got: %i", sizeof(PlayerProfile_Struct), lengths[1]); diff --git a/zone/zonedb.h b/zone/zonedb.h index 218654dc1..d0e70b995 100644 --- a/zone/zonedb.h +++ b/zone/zonedb.h @@ -252,8 +252,9 @@ public: bool GetAccountInfoForLogin(uint32 account_id, int16* admin = 0, char* account_name = 0, uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = 0); bool GetAccountInfoForLogin_result(MYSQL_RES* result, int16* admin = 0, char* account_name = 0, - uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = nullptr, - uint32* account_creation = 0); + uint32* lsaccountid = 0, uint8* gmspeed = 0, bool* revoked = 0, bool* gmhideme = nullptr, + uint32* account_creation = 0); + bool GetCharacterInfoForLogin_result(MYSQL_RES* result, uint32* character_id = 0, char* current_zone = 0, PlayerProfile_Struct* pp = 0, Inventory* inv = 0, ExtendedProfile_Struct *ext = 0, uint32* pplen = 0, uint32* guilddbid = 0, uint8* guildrank = 0, uint8 *class_= 0, uint8 *level = 0, bool *LFP = 0, @@ -268,6 +269,16 @@ public: void SavePetInfo(Client *c); void RemoveTempFactions(Client *c); + /* Player Profile Loaders */ + bool LoadCharacterData(uint32 character_id, PlayerProfile_Struct* pp); + bool LoadCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); + + /* Player Profile Saves */ + + bool SaveCharacterCurrency(uint32 character_id, PlayerProfile_Struct* pp); + bool SaveCharacterData(uint32 character_id, uint32 account_id, PlayerProfile_Struct* pp); + bool SaveCharacterAA(uint32 character_id, uint32 aa_id, uint32 current_level); + /* * Character Inventory */ diff --git a/zone/zoning.cpp b/zone/zoning.cpp index b50e43d33..1b64fef3c 100644 --- a/zone/zoning.cpp +++ b/zone/zoning.cpp @@ -354,7 +354,7 @@ void Client::DoZoneSuccess(ZoneChange_Struct *zc, uint16 zone_id, uint32 instanc m_pp.zoneInstance = instance_id; //Force a save so its waiting for them when they zone - Save(2); + Save(2); if (zone_id == zone->GetZoneID() && instance_id == zone->GetInstanceID()) { // No need to ask worldserver if we're zoning to ourselves (most