void Player::_SaveInventory() { // force items in buyback slots to new state // and remove those that aren't already for (uint8 i = BUYBACK_SLOT_START; i < BUYBACK_SLOT_END; i++) { Item *item = m_items[i]; if (!item || item->GetState() == ITEM_NEW) continue; CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", item->GetGUIDLow()); m_items[i]->FSetState(ITEM_NEW); } // update enchantment durations for(EnchantDurationList::iterator itr = m_enchantDuration.begin();itr != m_enchantDuration.end();++itr) { itr->item->SetEnchantmentDuration(itr->slot,itr->leftduration); } // if no changes if (m_itemUpdateQueue.empty()) return; // do not save if the update queue is corrupt bool error = false; for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) { Item *item = m_itemUpdateQueue[i]; if(!item || item->GetState() == ITEM_REMOVED) continue; Item *test = GetItemByPos( item->GetBagSlot(), item->GetSlot()); if (test == NULL) { sLog.outError("Player::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the player doesn't have an item at that position!", item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow()); error = true; } else if (test != item) { sLog.outError("Player::_SaveInventory - the bag(%d) and slot(%d) values for the item with guid %d are incorrect, the item with guid %d is there instead!", item->GetBagSlot(), item->GetSlot(), item->GetGUIDLow(), test->GetGUIDLow()); error = true; } } if (error) { sLog.outError("Player::_SaveInventory - one or more errors occurred save aborted!"); ChatHandler(this).SendSysMessage(LANG_ITEM_SAVE_FAILED); return; } for(size_t i = 0; i < m_itemUpdateQueue.size(); i++) { Item *item = m_itemUpdateQueue[i]; if(!item) continue; Bag *container = item->GetContainer(); uint32 bag_guid = container ? container->GetGUIDLow() : 0; switch(item->GetState()) { case ITEM_NEW: CharacterDatabase.PExecute("INSERT INTO character_inventory (guid,bag,slot,item,item_template) VALUES ('%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetGUIDLow(), item->GetEntry()); break; case ITEM_CHANGED: CharacterDatabase.PExecute("UPDATE character_inventory SET guid='%u', bag='%u', slot='%u', item_template='%u' WHERE item='%u'", GetGUIDLow(), bag_guid, item->GetSlot(), item->GetEntry(), item->GetGUIDLow()); break; case ITEM_REMOVED: CharacterDatabase.PExecute("DELETE FROM character_inventory WHERE item = '%u'", item->GetGUIDLow()); break; case ITEM_UNCHANGED: break; } item->SaveToDB(); // item have unchanged inventory record and can be save standalone } m_itemUpdateQueue.clear(); } void Player::_SaveMail() { if (!m_mailsLoaded) return; for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); itr++) { Mail *m = (*itr); if (m->state == MAIL_STATE_CHANGED) { CharacterDatabase.PExecute("UPDATE mail SET itemTextId = '%u',has_items = '%u',expire_time = '" I64FMTD "', deliver_time = '" I64FMTD "',money = '%u',cod = '%u',checked = '%u' WHERE id = '%u'", m->itemTextId, m->HasItems() ? 1 : 0, (uint64)m->expire_time, (uint64)m->deliver_time, m->money, m->COD, m->checked, m->messageID); if(m->removedItems.size()) { for(std::vector::iterator itr2 = m->removedItems.begin(); itr2 != m->removedItems.end(); ++itr2) CharacterDatabase.PExecute("DELETE FROM mail_items WHERE item_guid = '%u'", *itr2); m->removedItems.clear(); } m->state = MAIL_STATE_UNCHANGED; } else if (m->state == MAIL_STATE_DELETED) { if (m->HasItems()) for(std::vector::iterator itr2 = m->items.begin(); itr2 != m->items.end(); ++itr2) CharacterDatabase.PExecute("DELETE FROM item_instance WHERE guid = '%u'", itr2->item_guid); if (m->itemTextId) CharacterDatabase.PExecute("DELETE FROM item_text WHERE id = '%u'", m->itemTextId); CharacterDatabase.PExecute("DELETE FROM mail WHERE id = '%u'", m->messageID); CharacterDatabase.PExecute("DELETE FROM mail_items WHERE mail_id = '%u'", m->messageID); } } //deallocate deleted mails... for (PlayerMails::iterator itr = m_mail.begin(); itr != m_mail.end(); ) { if ((*itr)->state == MAIL_STATE_DELETED) { Mail* m = *itr; m_mail.erase(itr); delete m; itr = m_mail.begin(); } else ++itr; } m_mailsUpdated = false; } void Player::_SaveQuestStatus() { // we don't need transactions here. for( QuestStatusMap::iterator i = mQuestStatus.begin( ); i != mQuestStatus.end( ); ++i ) { switch (i->second.uState) { case QUEST_NEW : CharacterDatabase.PExecute("INSERT INTO character_queststatus (guid,quest,status,rewarded,explored,timer,mobcount1,mobcount2,mobcount3,mobcount4,itemcount1,itemcount2,itemcount3,itemcount4) " "VALUES ('%u', '%u', '%u', '%u', '%u', '" I64FMTD "', '%u', '%u', '%u', '%u', '%u', '%u', '%u', '%u')", GetGUIDLow(), i->first, i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3]); break; case QUEST_CHANGED : CharacterDatabase.PExecute("UPDATE character_queststatus SET status = '%u',rewarded = '%u',explored = '%u',timer = '" I64FMTD "',mobcount1 = '%u',mobcount2 = '%u',mobcount3 = '%u',mobcount4 = '%u',itemcount1 = '%u',itemcount2 = '%u',itemcount3 = '%u',itemcount4 = '%u' WHERE guid = '%u' AND quest = '%u' ", i->second.m_status, i->second.m_rewarded, i->second.m_explored, uint64(i->second.m_timer / 1000 + sWorld.GetGameTime()), i->second.m_creatureOrGOcount[0], i->second.m_creatureOrGOcount[1], i->second.m_creatureOrGOcount[2], i->second.m_creatureOrGOcount[3], i->second.m_itemcount[0], i->second.m_itemcount[1], i->second.m_itemcount[2], i->second.m_itemcount[3], GetGUIDLow(), i->first ); break; case QUEST_UNCHANGED: break; }; i->second.uState = QUEST_UNCHANGED; } } void Player::_SaveDailyQuestStatus() { if(!m_DailyQuestChanged) return; m_DailyQuestChanged = false; // save last daily quest time for all quests: we need only mostly reset time for reset check anyway // we don't need transactions here. CharacterDatabase.PExecute("DELETE FROM character_queststatus_daily WHERE guid = '%u'",GetGUIDLow()); for(uint32 quest_daily_idx = 0; quest_daily_idx < PLAYER_MAX_DAILY_QUESTS; ++quest_daily_idx) if(GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx)) CharacterDatabase.PExecute("INSERT INTO character_queststatus_daily (guid,quest,time) VALUES ('%u', '%u','" I64FMTD "')", GetGUIDLow(), GetUInt32Value(PLAYER_FIELD_DAILY_QUESTS_1+quest_daily_idx),uint64(m_lastDailyQuestTime)); } void Player::_SaveReputation() { for(FactionsList::iterator itr = m_factions.begin(); itr != m_factions.end(); ++itr) { if (itr->second.Changed) { CharacterDatabase.PExecute("DELETE FROM character_reputation WHERE guid = '%u' AND faction='%u'", GetGUIDLow(), itr->second.ID); CharacterDatabase.PExecute("INSERT INTO character_reputation (guid,faction,standing,flags) VALUES ('%u', '%u', '%i', '%u')", GetGUIDLow(), itr->second.ID, itr->second.Standing, itr->second.Flags); itr->second.Changed = false; } } } void Player::_SaveSpells() { for (PlayerSpellMap::const_iterator itr = m_spells.begin(), next = m_spells.begin(); itr != m_spells.end(); itr = next) { ++next; if (itr->second->state == PLAYERSPELL_REMOVED || itr->second->state == PLAYERSPELL_CHANGED) CharacterDatabase.PExecute("DELETE FROM character_spell WHERE guid = '%u' and spell = '%u'", GetGUIDLow(), itr->first); if (itr->second->state == PLAYERSPELL_NEW || itr->second->state == PLAYERSPELL_CHANGED) CharacterDatabase.PExecute("INSERT INTO character_spell (guid,spell,slot,active) VALUES ('%u', '%u', '%u','%u')", GetGUIDLow(), itr->first, itr->second->slotId,itr->second->active ? 1 : 0); if (itr->second->state == PLAYERSPELL_REMOVED) _removeSpell(itr->first); else itr->second->state = PLAYERSPELL_UNCHANGED; } }