Index: src/map/ai/ai_char_normal.cpp =================================================================== --- src/map/ai/ai_char_normal.cpp (revision 2793) +++ src/map/ai/ai_char_normal.cpp (working copy) @@ -97,6 +97,8 @@ m_PChar->pushPacket(new CMessageBasicPacket(m_PChar, m_PChar, 0, 0, MSGBASIC_CANT_BE_USED_IN_AREA)); } + m_PChar->AddPlayTime(); + switch (m_ActionType) { case ACTION_NONE: break; Index: src/map/charentity.cpp =================================================================== --- src/map/charentity.cpp (revision 2793) +++ src/map/charentity.cpp (working copy) @@ -101,6 +101,8 @@ m_lastBcnmTimePrompt = 0; m_AHHistoryTimestamp = 0; m_DeathTimestamp = 0; + m_PlayTime = 0; + m_ZoneTimer = 0; m_EquipFlag = 0; m_EquipBlock = 0; @@ -301,4 +303,17 @@ //PLatentEffectContainer->CheckLatentsHP(health.mp); return abs(mp); -} \ No newline at end of file +} + + +void CCharEntity::SetPlayTime(uint32 setTime) +{ + m_PlayTime = setTime; +} + +void CCharEntity::AddPlayTime() +{ + m_ZoneTimer++; + if((m_ZoneTimer % 2) == 0) + m_PlayTime++; +} Index: src/map/charentity.h =================================================================== --- src/map/charentity.h (revision 2793) +++ src/map/charentity.h (working copy) @@ -266,6 +266,10 @@ std::vector m_ah_history; // AH history list (в будущем нужно использовать UContainer) + void SetPlayTime(uint32); // Set playtime from database + void AddPlayTime(); // Add playtime every second + uint32 __inline const& GetPlayTime() { return m_PlayTime; }; + CCharEntity(); // конструктор ~CCharEntity(); // деструктор @@ -280,6 +284,9 @@ CItemContainer* m_Mogsack; PacketList_t PacketList; // в этом списке хранятся все пакеты, предназначенные для отправки персонажу + + uint32 m_ZoneTimer; + uint32 m_PlayTime; }; #endif Index: src/map/charutils.cpp =================================================================== --- src/map/charutils.cpp (revision 2793) +++ src/map/charutils.cpp (working copy) @@ -367,6 +367,8 @@ PChar->profile.nation = (uint8)Sql_GetIntData(SqlHandle,13); + PChar->SetPlayTime(Sql_GetUIntData(SqlHandle, 21)); + size_t length = 0; int8* quests = NULL; Sql_GetData(SqlHandle,14,&quests,&length); @@ -3770,5 +3772,9 @@ Sql_Query(SqlHandle, fmtQuery, (uint32)time(NULL), PChar->id); } +void SavePlayTime(CCharEntity* PChar) +{ + Sql_Query(SqlHandle, "UPDATE chars SET playtime = '%u' WHERE charid = '%u' LIMIT 1;", PChar->GetPlayTime(), PChar->id); +} } // namespace charutils Index: src/map/charutils.h =================================================================== --- src/map/charutils.h (revision 2793) +++ src/map/charutils.h (working copy) @@ -134,6 +134,7 @@ void SaveCharSkills(CCharEntity* PChar, uint8 skillID); // сохраняем указанный skill персонажа void SaveCharPoints(CCharEntity* PChar); // Conquest point, Nation TP void SaveDeathTime(CCharEntity* PChar); // Saves when this character last died. + void SavePlayTime(CCharEntity* PChar); // Saves this characters total play time. bool hasMogLockerAccess(CCharEntity* PChar); // true if have access, false otherwise. uint32 AddExpBonus(CCharEntity* PChar, uint32 exp); Index: src/map/map.cpp =================================================================== --- src/map/map.cpp (revision 2793) +++ src/map/map.cpp (working copy) @@ -204,6 +204,7 @@ CTaskMgr::getInstance()->AddTask("time_server", gettick(), NULL, CTaskMgr::TASK_INTERVAL, time_server, 2400); CTaskMgr::getInstance()->AddTask("map_cleanup", gettick(), NULL, CTaskMgr::TASK_INTERVAL, map_cleanup, 5000); + CTaskMgr::getInstance()->AddTask("save_playtime", gettick(), NULL, CTaskMgr::TASK_INTERVAL, save_playtime, 600000); // Update this every 10 minutes. CREATE(g_PBuff, int8, map_config.buffer_size + 20); CREATE(PTempBuff, int8, map_config.buffer_size + 20); @@ -661,6 +662,8 @@ { Sql_Query(SqlHandle,"DELETE FROM accounts_sessions WHERE charid = %u",map_session_data->PChar->id); + charutils::SavePlayTime(map_session_data->PChar); + uint64 port64 = map_session_data->client_port; uint64 ipp = map_session_data->client_addr; ipp |= port64<<32; Index: src/map/packet_system.cpp =================================================================== --- src/map/packet_system.cpp (revision 2793) +++ src/map/packet_system.cpp (working copy) @@ -276,6 +276,8 @@ charutils::SaveCharPosition(PChar); charutils::SaveZonesVisited(PChar); + charutils::SavePlayTime(PChar); + PChar->pushPacket(new CDownloadingDataPacket()); PChar->pushPacket(new CZoneInPacket(PChar,EventID)); PChar->pushPacket(new CZoneVisitedPacket(PChar)); Index: src/map/packets/zone_in.cpp =================================================================== --- src/map/packets/zone_in.cpp (revision 2793) +++ src/map/packets/zone_in.cpp (working copy) @@ -181,7 +181,7 @@ WBUFB(data,(0xAF)-4) = PChar->loc.zone->CanUseMisc(MISC_MOGMENU); // флаг, позволяет использовать mog menu за пределами mog house } - WBUFL(data,(0xA0)-4) = 0x00000000; // время, проведенное персонажем в игре с момента создания + WBUFL(data,(0xA0)-4) = PChar->GetPlayTime(); // время, проведенное персонажем в игре с момента создания // current death timestamp is less than an hour ago and the player is dead. if (PChar->m_DeathTimestamp > 0 && ((time(NULL)-PChar->m_DeathTimestamp) < (60*60)) && PChar->isDead()) { Index: src/map/time_server.cpp =================================================================== --- src/map/time_server.cpp (revision 2793) +++ src/map/time_server.cpp (working copy) @@ -30,6 +30,7 @@ #include "zoneutils.h" #include "conquest_system.h" #include "lua/luautils.h" +#include "charutils.h" int32 time_server(uint32 tick,CTaskMgr::CTask* PTask) @@ -62,4 +63,10 @@ CTransportHandler::getInstance()->TransportTimer(); return 0; -} \ No newline at end of file +} + +int32 save_playtime(uint32 tick, CTaskMgr::CTask* PTask) +{ + zoneutils::SavePlayTime(); + return 0; +} Index: src/map/time_server.h =================================================================== --- src/map/time_server.h (revision 2793) +++ src/map/time_server.h (working copy) @@ -29,5 +29,6 @@ int32 time_server(uint32 tick,CTaskMgr::CTask*); +int32 save_playtime(uint32 tick, CTaskMgr::CTask*); #endif Index: src/map/zone.cpp =================================================================== --- src/map/zone.cpp (revision 2793) +++ src/map/zone.cpp (working copy) @@ -1303,6 +1303,18 @@ } } +void CZone::SavePlayTime() +{ + if(!m_charList.empty()) + { + for(EntityList_t::const_iterator it = m_charList.begin(); it != m_charList.end(); ++it) + { + CCharEntity* PChar = (CCharEntity*)it->second; + charutils::SavePlayTime(PChar); + } + } +} + /************************************************************************ * * * * Index: src/map/zone.h =================================================================== --- src/map/zone.h (revision 2793) +++ src/map/zone.h (working copy) @@ -435,6 +435,7 @@ void SpawnNPCs(CCharEntity* PChar); // отображаем NPCs в зоне void SpawnMoogle(CCharEntity* PChar); // отображаем Moogle в MogHouse void SpawnTransport(CCharEntity* PChar); // отображаем транспорт + void SavePlayTime(); void WideScan(CCharEntity* PChar, uint16 radius); // сканирование местности с заданным радиусом Index: src/map/zoneutils.cpp =================================================================== --- src/map/zoneutils.cpp (revision 2793) +++ src/map/zoneutils.cpp (working copy) @@ -94,6 +94,15 @@ ShowDebug(CL_CYAN"UpdateWeather Finished\n" CL_RESET); } +void SavePlayTime() +{ + for(int32 ZoneID = 0; ZoneID < 256; ZoneID++) + { + g_PZoneList[ZoneID]->SavePlayTime(); + } + ShowDebug(CL_CYAN"Player playtime saving finished\n" CL_RESET); +} + /************************************************************************ * * * Возвращаем указатель на класс зоны с указанным ID. * Index: src/map/zoneutils.h =================================================================== --- src/map/zoneutils.h (revision 2793) +++ src/map/zoneutils.h (working copy) @@ -45,6 +45,7 @@ void UpdateWeather(); // обновляем погоду в зонах void TOTDCharnge(TIMETYPE TOTD); // реакция мира на смену времени суток + void SavePlayTime(); REGIONTYPE GetCurrentRegion(uint8 ZoneID); CONTINENTTYPE GetCurrentContinent(uint8 ZoneID);