// SaveManager.cpp // This class runs a thread which handles all the players' changes // It keeps a connection to the SQL DB open // Eventually this could become a separate process and run on another server PC. #include "Net7.h" #include "SaveManager.h" #include "PacketMethods.h" enum experience_type { XP_COMBAT, XP_EXPLORE, XP_TRADE }; SaveManager::SaveManager() { m_SaveBuffer = new CircularBuffer(0x20000, 2048); m_SaveQueue = new MessageQueue(m_SaveBuffer); #ifdef WIN32 UINT uiThreadId = 0; m_SaveThreadHandle = (HANDLE)_beginthreadex(NULL, 0, StartSaveThread, this, CREATE_SUSPENDED, &uiThreadId); #else pthread_create(&m_SaveThreadHandle , NULL, &StartSaveThread, (void *) this); #endif } SaveManager::~SaveManager() { // TODO: ensure thread is halted and shuts down ok, having saved everyone's status } void SaveManager::RunSaveThread() { int length; EnbSaveHeader *header; unsigned char msg[SAVE_MESSAGE_MAX_LENGTH]; //message will be under 256 or the 'AddMessage' method will not process it //open the database connection m_SQL_Conn.connect("net7_user", g_MySQL_Host, g_MySQL_User, g_MySQL_Pass); m_SaveThreadRunning = true; while (!g_ServerShutdown) { #ifdef WIN32 while (m_SaveQueue->CheckQueue(msg, &length, SAVE_MESSAGE_MAX_LENGTH)) //check if there are any messages in the queue, if there are write them into the 'msg' buffer { //process this message //format is opcode/length/message header = (EnbSaveHeader*)msg; unsigned char *data = (msg + sizeof(EnbSaveHeader)); //process opcode accordingly HandleSaveCode(header->save_code, header->player_id, header->size, data); } SuspendThread(m_SaveThreadHandle); Sleep(2); #else m_SaveQueue->BlockingCheckQueue(msg, &length, SAVE_MESSAGE_MAX_LENGTH); //Wait for any messages in the queue, if there are write them into the 'msg' buffer header = (EnbSaveHeader*)msg; unsigned char *data = (msg + sizeof(EnbSaveHeader)); //process opcode accordingly HandleSaveCode(header->save_code, header->player_id, header->size, data); #endif } } void SaveManager::AddSaveMessage(short save_code, long player_id, short length, unsigned char *data) { if (!m_SaveThreadRunning) { LogMessage("ERROR!: Save thread not running!!\n"); return; } unsigned char pData[SAVE_MESSAGE_MAX_LENGTH]; if (length + 4 > SAVE_MESSAGE_MAX_LENGTH) { LogMessage("Recv message overflow: length = %d\n", length); return; } *((short*) &pData[0]) = length; *((short*) &pData[2]) = save_code; *((long* ) &pData[4]) = player_id; if (data) { memcpy(pData + sizeof(short)*2 + sizeof(long), data, length); } m_SaveQueue->Add(pData, length+sizeof(EnbSaveHeader), player_id); #ifdef WIN32 //Only necessary on win32 because we are using a blocking queue on linux. //TODO: Modify the windows code to also use the blocking queue instead. ResumeThread(m_SaveThreadHandle); #endif } void SaveManager::HandleSaveCode(short save_code, long player_id, short bytes, unsigned char *data) { switch (save_code) { case SAVE_CODE_ADVANCE_LEVEL: HandleAdvanceLevel(player_id, bytes, data); break; case SAVE_CODE_ADVANCE_SKILL: HandleAdvanceSkill(player_id, bytes, data); break; case SAVE_CODE_CHANGE_INVENTORY: HandleChangeInventory(player_id, bytes, data); break; case SAVE_CODE_CHANGE_EQUIPMENT: HandleChangeEquipment(player_id, bytes, data); break; case SAVE_CODE_AWARD_XP: HandleAwardXP(player_id, bytes, data); break; case SAVE_CODE_CREDIT_LEVEL: HandleCreditChange(player_id, bytes, data); break; case SAVE_CODE_STORE_POSITION: HandleStorePosition(player_id, bytes, data); break; case SAVE_CODE_ADVANCE_MISSION: HandleAdvanceMission(player_id, bytes, data); break; case SAVE_CODE_CHARACTER_PROGRESS_WIPE: HandleWipeCharacter(player_id); break; case SAVE_CODE_FULL_CHARACTER_WIPE: HandleFullWipeCharacter(player_id); break; case SAVE_CODE_MISSION_FLAGS: HandleAdvanceMissionFlags(player_id, bytes, data); break; case SAVE_CODE_CHANGE_AMMO: HandleChangeAmmo(player_id, bytes, data); break; case SAVE_CODE_HULL_UPGRADE: HandleHullUpgrade(player_id, bytes, data); break; case SAVE_CODE_HULL_LEVEL_CHANGE: HandleHullLevelChange(player_id, bytes, data); break; case SAVE_CODE_MISSION_COMPLETE: HandleMissionComplete(player_id, bytes, data); break; case SAVE_CODE_DISCOVER_NAV: HandleDiscoverNav(player_id, bytes, data); break; case SAVE_CODE_EXPLORE_NAV: HandleExploreNav(player_id, bytes, data); break; case SAVE_CODE_SET_SKILLPOINTS: HandleSetSkillPoints(player_id, bytes, data); break; case SAVE_CODE_SET_STARBASE: HandleSetRegisteredStarbase(player_id, bytes, data); break; case SAVE_CODE_SET_ENERGY_LEVELS: HandleSaveEnergyLevels(player_id, bytes, data); break; default: LogMessage( "Bad save code : %d for player %x\n", save_code, (player_id&0x00FFFFFF) ); break; } } void SaveManager::HandleAdvanceLevel(long player_id, short bytes, unsigned char *data) { //player just levelled up. sql_query_c account_query (&m_SQL_Conn); u8 xp_type = *((u8 *) &data[0]); long new_level = *((long *) &data[1]); switch (xp_type) { case XP_COMBAT: sprintf(m_QueryStr, "UPDATE net7_user.avatar_info SET combat = '%ld' WHERE avatar_id = '%ld'", new_level, player_id); break; case XP_EXPLORE: sprintf(m_QueryStr, "UPDATE net7_user.avatar_info SET explore = '%ld' WHERE avatar_id = '%ld'", new_level, player_id); break; case XP_TRADE: sprintf(m_QueryStr, "UPDATE net7_user.avatar_info SET trade = '%ld' WHERE avatar_id = '%ld'", new_level, player_id); break; } account_query.run_query(m_QueryStr); } void SaveManager::HandleAdvanceSkill(long player_id, short bytes, unsigned char *data) { //player has just increased a skill sql_query_c account_query (&m_SQL_Conn); sql_result_c result; short skill_id = *((short *) &data[0]); short new_level= *((short *) &data[2]); //does this skill exist in the DB? //TODO:: create this entry when the skill is awarded, then just run 'UPDATE' queries on it. sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_skill_levels WHERE avatar_id = '%ld' AND skill_id = '%d'", player_id, skill_id); account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { sprintf(m_QueryStr, "UPDATE net7_user.avatar_skill_levels SET skill_level = '%d' WHERE avatar_id = '%ld' AND skill_id = '%d'", new_level, player_id, skill_id); account_query.run_query(m_QueryStr); } else { //we need to create a new entry sql_query SkillBuilder; SkillBuilder.Clear(); SkillBuilder.SetTable("avatar_skill_levels"); SkillBuilder.AddData("avatar_id", player_id); SkillBuilder.AddData("skill_id", skill_id); SkillBuilder.AddData("skill_level", new_level); if (!account_query.run_query(SkillBuilder.CreateQuery())) { LogMessage("Could not save Skill Info for id %d\n", player_id ); } } } void SaveManager::HandleChangeInventory(long player_id, short bytes, unsigned char *data) { //player has just had an inventory change of some sort sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 inventory_slot = *((u8 *) &data[0]); u8 inventory_type = *((u8 *) &data[1]); short stack_level = *((short *) &data[2]); short trade_stack = *((short *) &data[4]); float quality = *((float *) &data[6]); long item_id = *((long *) &data[10]); unsigned long cost = *((unsigned long *) &data[14]); switch (inventory_type) { case PLAYER_INVENTORY: sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_inventory_items WHERE avatar_id = '%ld' AND inventory_slot = '%d'", player_id, inventory_slot); break; case PLAYER_VAULT: sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_vault_items WHERE avatar_id = '%ld' AND inventory_slot = '%d'", player_id, inventory_slot); break; } //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update the item switch (inventory_type) { case PLAYER_INVENTORY: sprintf(m_QueryStr, "UPDATE net7_user.avatar_inventory_items SET item_id = '%ld', stack_level = '%d', trade_stack = '%d', quality = '%f', cost = '%ld' WHERE avatar_id = '%ld' AND inventory_slot = '%d'", item_id, stack_level, trade_stack, quality, cost, player_id, inventory_slot); break; case PLAYER_VAULT: sprintf(m_QueryStr, "UPDATE net7_user.avatar_vault_items SET item_id = '%ld', stack_level = '%d', trade_stack = '%d', quality = '%f', cost = '%ld' WHERE avatar_id = '%ld' AND inventory_slot = '%d'", item_id, stack_level, trade_stack, quality, cost, player_id, inventory_slot); break; } account_query.run_query(m_QueryStr); } else { //we need to create a new entry for this item, that's ok sql_query ItemBuilder; ItemBuilder.Clear(); switch (inventory_type) { case PLAYER_INVENTORY: ItemBuilder.SetTable("avatar_inventory_items"); break; case PLAYER_VAULT: ItemBuilder.SetTable("avatar_vault_items"); break; } ItemBuilder.AddData("avatar_id", player_id); ItemBuilder.AddData("item_id", item_id); ItemBuilder.AddData("stack_level", stack_level); ItemBuilder.AddData("trade_stack", trade_stack); ItemBuilder.AddData("quality", quality); ItemBuilder.AddData("inventory_slot", inventory_slot); ItemBuilder.AddData("cost", cost); if (!account_query.run_query(ItemBuilder.CreateQuery())) { LogMessage("Could not save Inventory Info for id %d [item id %d]\n", player_id, item_id ); } } } void SaveManager::HandleChangeEquipment(long player_id, short bytes, unsigned char *data) { //player has just had an equipment change sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 equipment_slot = *((u8 *) &data[0]); float quality = *((float *) &data[1]); long item_id = *((long *) &data[5]); sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_equipment WHERE avatar_id = '%ld' AND equipment_slot = '%d'", player_id, equipment_slot); //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update the equipment slot sprintf(m_QueryStr, "UPDATE net7_user.avatar_equipment SET item_id = '%ld', quality = '%f' WHERE avatar_id = '%ld' AND equipment_slot = '%d'", item_id, quality, player_id, equipment_slot); account_query.run_query(m_QueryStr); } else { //we need to create a new entry for this item, that's ok sql_query EquipBuilder; EquipBuilder.Clear(); EquipBuilder.SetTable("avatar_equipment"); EquipBuilder.AddData("avatar_id", player_id); EquipBuilder.AddData("item_id", item_id); EquipBuilder.AddData("quality", quality); EquipBuilder.AddData("equipment_slot", equipment_slot); if (!account_query.run_query(EquipBuilder.CreateQuery())) { LogMessage("Could not save Equip Info for id %d\n", player_id ); } } } void SaveManager::HandleChangeAmmo(long player_id, short bytes, unsigned char *data) { //player has just had an ammo change sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 equipment_slot = *((u8 *) &data[0]); short ammo_stack = *((short *) &data[1]); float quality = *((float *) &data[3]); long item_id = *((long *) &data[7]); sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_ammo WHERE avatar_id = '%ld' AND equipment_slot = '%d'", player_id, equipment_slot); //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update the equipment slot sprintf(m_QueryStr, "UPDATE net7_user.avatar_ammo SET item_id = '%ld', quality = '%f', ammo_stack = '%d' WHERE avatar_id = '%ld' AND equipment_slot = '%d'", item_id, quality, ammo_stack, player_id, equipment_slot); account_query.run_query(m_QueryStr); } else { //we need to create a new entry for this item, that's ok sql_query EquipBuilder; EquipBuilder.Clear(); EquipBuilder.SetTable("avatar_ammo"); EquipBuilder.AddData("avatar_id", player_id); EquipBuilder.AddData("item_id", item_id); EquipBuilder.AddData("quality", quality); EquipBuilder.AddData("equipment_slot", equipment_slot); EquipBuilder.AddData("ammo_stack", ammo_stack); if (!account_query.run_query(EquipBuilder.CreateQuery())) { LogMessage("Could not save Ammo Info for id %d\n", player_id ); } } } void SaveManager::HandleAwardXP(long player_id, short bytes, unsigned char *data) { //player just received XP, bar is now at a new level sql_query_c account_query (&m_SQL_Conn); u8 xp_type = *((u8 *) &data[0]); float new_level = *((float *) &data[1]); switch (xp_type) { case XP_COMBAT: sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET combat_bar_level = '%f' WHERE avatar_id = '%ld'", new_level, player_id); break; case XP_EXPLORE: sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET explore_bar_level = '%f' WHERE avatar_id = '%ld'", new_level, player_id); break; case XP_TRADE: sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET trade_bar_level = '%f' WHERE avatar_id = '%ld'", new_level, player_id); break; } account_query.run_query(m_QueryStr); } void SaveManager::HandleCreditChange(long player_id, short bytes, unsigned char *data) { //player just received XP, bar is now at a new level sql_query_c account_query (&m_SQL_Conn); u64 credits = *((u64 *) &data[0]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET credits = '%I64d' WHERE avatar_id = '%ld'", credits, player_id); account_query.run_query(m_QueryStr); } void SaveManager::HandleStorePosition(long player_id, short bytes, unsigned char *data) { //get the position stored //get position out of data float position[3]; float orientation[4]; long sector_id; position[0] = *((float *) &data[0]); position[1] = *((float *) &data[4]); position[2] = *((float *) &data[8]); orientation[0] = *((float *) &data[12]); orientation[1] = *((float *) &data[16]); orientation[2] = *((float *) &data[20]); orientation[3] = *((float *) &data[24]); sector_id = *((long *) &data[28]); //now store data into DB sql_query_c account_query (&m_SQL_Conn); sprintf(m_QueryStr, "UPDATE net7_user.avatar_position SET posx = '%.2f', posy = '%.2f', posz = '%.2f', ori_w = '%f', ori_x = '%f', ori_y = '%f', ori_z = '%f', sector_id = '%ld' WHERE avatar_id = '%ld'", position[0], position[1], position[2], orientation[0], orientation[1], orientation[2], orientation[3], sector_id, player_id); account_query.run_query(m_QueryStr); } void SaveManager::HandleAdvanceMission(long player_id, short bytes, unsigned char *data) { //player has just either been awarded a mission or has advanced in one sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 mission_slot = *((u8 *) &data[0]); long mission_id = *((long *) &data[1]); short mission_stage = *((short *) &data[5]); sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_mission_progress WHERE avatar_id = '%ld' AND mission_slot = '%d'", player_id, mission_slot); //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update this mission and blank the mission flags sprintf(m_QueryStr, "UPDATE net7_user.avatar_mission_progress SET stage_num = '%d', mission_flags = '0' WHERE avatar_id = '%ld' AND mission_slot = '%d'", mission_stage, player_id, mission_slot); account_query.run_query(m_QueryStr); } else { //we need to create a new entry for this mission sql_query MissionBuilder; MissionBuilder.Clear(); MissionBuilder.SetTable("avatar_mission_progress"); MissionBuilder.AddData("avatar_id", player_id); MissionBuilder.AddData("mission_id", mission_id); MissionBuilder.AddData("mission_slot", mission_slot); MissionBuilder.AddData("mission_flags", 0); MissionBuilder.AddData("stage_num", mission_stage); if (!account_query.run_query(MissionBuilder.CreateQuery())) { LogMessage("Could not save Mission Info for id %d\n", player_id ); } } } void SaveManager::HandleAdvanceMissionFlags(long player_id, short bytes, unsigned char *data) { //player has just had mission flags changed. This is only relevant if the mission exists in the DB //so just do a simple DB commit. sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 mission_slot = *((u8 *) &data[0]); long mission_flags = *((long *) &data[1]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_mission_progress SET mission_flags = '%ld' WHERE avatar_id = '%ld' AND mission_slot = '%d'", mission_flags, player_id, mission_slot); account_query.run_query(m_QueryStr); } void SaveManager::HandleHullUpgrade(long player_id, short bytes, unsigned char *data) { //player has just had an hull upgrade change (or this is a new player) sql_query_c account_query (&m_SQL_Conn); sql_result_c result; u8 player_rank_name = *((u8 *) &data[0]); u8 hull_upgrade_level = *((u8 *) &data[1]); float max_hull_points = *((float *) &data[2]); u8 cargo_space = *((u8 *) &data[6]); u8 weapon_slots = *((u8 *) &data[7]); u8 device_slots = *((u8 *) &data[8]); u8 warp_power_level = *((u8 *) &data[9]); u8 engine_thrust_type = *((u8 *) &data[10]); sprintf(m_QueryStr, "SELECT * FROM net7_user.avatar_level_info WHERE avatar_id = '%ld'", player_id); //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update the level info row sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET player_rank_name = '%d', hull_upgrade_level = '%d', max_hull_points = '%.2f', cargo_space = '%d', weapon_slots = '%d', device_slots = '%d' WHERE avatar_id = '%ld'", player_rank_name, hull_upgrade_level, max_hull_points, cargo_space, weapon_slots, device_slots, player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET engine_thrust_type = '%d', warp_power_level = '%d' WHERE avatar_id = '%ld'", engine_thrust_type, warp_power_level, player_id); account_query.run_query(m_QueryStr); } else { //we need to create a new entry for this player, that's ok sql_query LevelBuilder; LevelBuilder.Clear(); LevelBuilder.SetTable("avatar_level_info"); LevelBuilder.AddData("avatar_id", player_id); LevelBuilder.AddData("player_rank_name", player_rank_name); LevelBuilder.AddData("hull_upgrade_level", hull_upgrade_level); LevelBuilder.AddData("max_hull_points", max_hull_points); LevelBuilder.AddData("cargo_space", cargo_space); LevelBuilder.AddData("weapon_slots", weapon_slots); LevelBuilder.AddData("device_slots", device_slots); LevelBuilder.AddData("combat_bar_level", 0.0f); LevelBuilder.AddData("explore_bar_level", 0.0f); LevelBuilder.AddData("trade_bar_level", 0.0f); LevelBuilder.AddData("warp_power_level", warp_power_level); LevelBuilder.AddData("engine_thrust_type", engine_thrust_type); LevelBuilder.AddData("hull_points", max_hull_points); LevelBuilder.AddData("credits", 0); LevelBuilder.AddData("skill_points", 0); //skill if (!account_query.run_query(LevelBuilder.CreateQuery())) { LogMessage("Could not save Avatar level Info for id %d\n", player_id ); } } } void SaveManager::HandleHullLevelChange(long player_id, short bytes, unsigned char *data) { //player has just had an hull level change sql_query_c account_query (&m_SQL_Conn); sql_result_c result; float hull_points = *((float *) &data[0]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET hull_points = '%.2f' WHERE avatar_id = '%ld'", hull_points, player_id); account_query.run_query(m_QueryStr); } void SaveManager::HandleMissionComplete(long player_id, short bytes, unsigned char *data) { //player has just completed a mission sql_query_c account_query (&m_SQL_Conn); sql_result_c result; long mission_id = *((long *) &data[0]); u8 mission_flags = *((u8 *) &data[4]); //first remove mission progress sprintf(m_QueryStr, "DELETE FROM net7_user.avatar_mission_progress WHERE avatar_id = '%ld' AND mission_id = '%ld'", player_id, mission_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "SELECT * FROM net7_user.missions_completed WHERE avatar_id = '%ld' AND mission_id = '%ld'", player_id, mission_id); //does this item exist in the DB? account_query.execute(m_QueryStr); account_query.store(&result); if (result.n_rows() != 0) { //yes, just update the info row sprintf(m_QueryStr, "UPDATE net7_user.missions_completed SET mission_completion_flags = '%d' WHERE avatar_id = '%ld' AND mission_id = '%ld'", mission_flags, player_id, mission_id); account_query.run_query(m_QueryStr); } else { sql_query MissionBuilder; MissionBuilder.Clear(); MissionBuilder.SetTable("missions_completed"); MissionBuilder.AddData("avatar_id", player_id); MissionBuilder.AddData("mission_id", mission_id); MissionBuilder.AddData("mission_completion_flags", mission_flags); account_query.run_query(MissionBuilder.CreateQuery()); } } //this method leaves the base character design, name and ship but resets them back to a starting condition. void SaveManager::HandleWipeCharacter(long player_id) { //ok remove all records of inventory, equipment, ammo, skills, levels & rank info sql_query_c account_query (&m_SQL_Conn); //remove position info sprintf(m_QueryStr, "DELETE FROM `avatar_position` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_level_info` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_ammo` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_inventory_items` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_vault_items` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_equipment` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_mission_progress` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "UPDATE net7_user.avatar_info SET combat = '0', explore = '0', trade = '0' WHERE avatar_id = '%ld'", player_id); account_query.run_query(m_QueryStr); } //this method removes all trace of the avatar in the database, must be used when the avatar is deleted via the client avatar character selector. void SaveManager::HandleFullWipeCharacter(long player_id) { sql_query_c account_query (&m_SQL_Conn); //remove position info sprintf(m_QueryStr, "DELETE FROM `avatar_position` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_level_info` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_ammo` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_inventory_items` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_vault_items` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_equipment` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `avatar_mission_progress` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); sprintf(m_QueryStr, "DELETE FROM `missions_completed` WHERE `avatar_id` = '%ld'", player_id); account_query.run_query(m_QueryStr); } #ifdef WIN32 UINT WINAPI SaveManager::StartSaveThread(LPVOID Param) { SaveManager* p_this = reinterpret_cast( Param ); p_this->RunSaveThread(); return 1; } #else void* SaveManager::StartSaveThread(void* Param) { SaveManager* p_this = reinterpret_cast( Param ); p_this->RunSaveThread(); return NULL; } #endif void SaveManager::HandleDiscoverNav(long player_id, short bytes, unsigned char *data) { //player has just discovered a nav, make a record sql_query_c account_query (&m_SQL_Conn); long object_uid = *((long *) &data[0]); sql_query ExploreBuilder; ExploreBuilder.Clear(); ExploreBuilder.SetTable("avatar_exploration"); ExploreBuilder.AddData("avatar_id", player_id); ExploreBuilder.AddData("object_id", object_uid); ExploreBuilder.AddData("explore_flags", DISCOVER_NAV); account_query.run_query(ExploreBuilder.CreateQuery()); } void SaveManager::HandleExploreNav(long player_id, short bytes, unsigned char *data) { //player has just explored a nav, update the record sql_query_c account_query (&m_SQL_Conn); long object_uid = *((long *) &data[0]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_exploration SET explore_flags = '%d' WHERE avatar_id = '%ld' AND object_id = '%ld'", EXPLORE_NAV, player_id, object_uid); account_query.run_query(m_QueryStr); } void SaveManager::HandleSetSkillPoints(long player_id, short bytes, unsigned char *data) { //set skill points sql_query_c account_query (&m_SQL_Conn); long skill_points = *((long *) &data[0]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET skill_points = '%ld' WHERE avatar_id = '%ld'", skill_points, player_id); account_query.run_query(m_QueryStr); } void SaveManager::HandleSetRegisteredStarbase(long player_id, short bytes, unsigned char *data) { //set skill points sql_query_c account_query (&m_SQL_Conn); long registered_starbase = *((long *) &data[0]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET registered_starbase = '%ld' WHERE avatar_id = '%ld'", registered_starbase, player_id); account_query.run_query(m_QueryStr); } void SaveManager::HandleSaveEnergyLevels(long player_id, short bytes, unsigned char *data) { //set skill points sql_query_c account_query (&m_SQL_Conn); float energy = *((float *) &data[0]); float shield = *((float *) &data[4]); sprintf(m_QueryStr, "UPDATE net7_user.avatar_level_info SET reactor_level = '%f', shield_level = '%f' WHERE avatar_id = '%ld'", energy, shield, player_id); account_query.run_query(m_QueryStr); }