diff options
author | Shauren <shauren.trinity@gmail.com> | 2023-11-21 12:25:22 +0100 |
---|---|---|
committer | funjoker <funjoker109@gmail.com> | 2023-12-01 23:28:35 +0100 |
commit | 070cd23b6cf2e985713b90455cb7f7c53535cbcf (patch) | |
tree | cfcd414ecc4d3ef05253140ce83897f693d6dcd3 | |
parent | b6e346eaf0ee9a1c0dc2c7977ac950b77c857ecf (diff) |
Core/Calendar: Implement different timezone support for ingame calendar
Closes #8390
Closes #29427
(cherry picked from commit b888b1b09f71a8b8b4a9d45c804a1f164fb65ac3)
47 files changed, 1188 insertions, 462 deletions
diff --git a/dep/boost/CMakeLists.txt b/dep/boost/CMakeLists.txt index 5d0f372594e..845f4ee8edc 100644 --- a/dep/boost/CMakeLists.txt +++ b/dep/boost/CMakeLists.txt @@ -29,7 +29,7 @@ else() set(BOOST_REQUIRED_VERSION 1.71) endif() -find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED system filesystem program_options iostreams regex) +find_package(Boost ${BOOST_REQUIRED_VERSION} REQUIRED system filesystem program_options iostreams regex locale) if(NOT Boost_FOUND) if(NOT DEFINED ENV{BOOST_ROOT} AND NOT DEFINED Boost_DIR AND NOT DEFINED BOOST_ROOT AND NOT DEFINED BOOSTROOT) diff --git a/sql/base/auth_database.sql b/sql/base/auth_database.sql index 32724d2ef56..8a82e84f05c 100644 --- a/sql/base/auth_database.sql +++ b/sql/base/auth_database.sql @@ -46,6 +46,7 @@ CREATE TABLE `account` ( `muteby` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', `locale` tinyint unsigned NOT NULL DEFAULT '0', `os` varchar(4) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `timezone_offset` smallint NOT NULL DEFAULT '0', `recruiter` int unsigned NOT NULL DEFAULT '0', `battlenet_account` int unsigned DEFAULT NULL, `battlenet_index` tinyint unsigned DEFAULT NULL, @@ -2759,6 +2760,7 @@ INSERT INTO `updates` VALUES ('2023_11_09_01_auth.sql','BC9BC28D41608A78166B5A38F3A7F598FBDB879D','RELEASED','2023-11-09 18:21:59',0), ('2023_11_14_00_auth.sql','192D729737C5E3332D7B5B9B7F9DBDD9626D7B98','RELEASED','2023-11-14 11:36:05',0), ('2023_11_15_00_auth.sql','DC89EA5C9D799C213B3E6A606F081697ADEF8250','RELEASED','2023-11-15 10:47:53',0), +('2023_11_21_00_auth.sql','146E5E6EF94C5DB78343372A8FDB32B062B80040','RELEASED','2023-11-21 11:24:11',0), ('2023_11_23_00_auth.sql','EC3D1289A07E387BF4D2AC94EEBE3A29483EAD3A','RELEASED','2023-11-23 02:39:18',0); /*!40000 ALTER TABLE `updates` ENABLE KEYS */; UNLOCK TABLES; diff --git a/sql/updates/auth/master/2023_11_21_00_auth.sql b/sql/updates/auth/master/2023_11_21_00_auth.sql new file mode 100644 index 00000000000..1dc190782d7 --- /dev/null +++ b/sql/updates/auth/master/2023_11_21_00_auth.sql @@ -0,0 +1 @@ +ALTER TABLE `account` ADD `timezone_offset` smallint NOT NULL DEFAULT '0' AFTER `os`; diff --git a/src/common/Utilities/Timer.h b/src/common/Time/Timer.h index e0ecb5b2d13..e0ecb5b2d13 100644 --- a/src/common/Utilities/Timer.h +++ b/src/common/Time/Timer.h diff --git a/src/common/Time/Timezone.cpp b/src/common/Time/Timezone.cpp new file mode 100644 index 00000000000..f7acfe5df5c --- /dev/null +++ b/src/common/Time/Timezone.cpp @@ -0,0 +1,179 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "Timezone.h" +#include "Hash.h" +#include "MapUtils.h" +#include "Util.h" +#include <boost/locale/date_time_facet.hpp> +#include <boost/locale/generator.hpp> +#include <chrono> +#include <unordered_map> + +namespace +{ +std::unordered_map<uint32, Minutes, std::identity> InitTimezoneHashDb() +{ +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS + + // Generate our hash db to match values sent in client authentication packets + std::unordered_map<uint32, Minutes, std::identity> hashToOffset; + std::chrono::system_clock::time_point dummmy; + for (std::chrono::time_zone const& zone : std::chrono::get_tzdb().zones) + { + std::chrono::sys_info sysInfo = zone.get_info(dummmy); + Minutes offsetMinutes = std::chrono::duration_cast<Minutes>(sysInfo.offset); + std::string offsetStr = Trinity::ToString(offsetMinutes.count()); + hashToOffset.emplace(Trinity::HashFnv1a(offsetStr), offsetMinutes); + } + +#else + // Pre-generated list of timezone offsets and their hashes for compilers (and their stl implementations) that dont support timezone api yet + std::unordered_map<uint32, Minutes, std::identity> hashToOffset = + { + { 0xAADC2D37u, -720min }, + { 0x362F107Bu, -690min }, + { 0x2C44C70Cu, -660min }, + { 0xB84A209Eu, -640min }, + { 0xBA3D57D1u, -630min }, + { 0x4040695Au, -600min }, + { 0xB65A75D0u, -570min }, + { 0xC8614DEBu, -540min }, + { 0x3A68BD26u, -510min }, + { 0x51E8096Cu, -480min }, + { 0x4DD8F896u, -420min }, + { 0x674B7C0Fu, -360min }, + { 0x633C6B39u, -300min }, + { 0x0BAD340Au, -240min }, + { 0x74B25683u, -225min }, + { 0x09B9FCD7u, -210min }, + { 0x150C169Bu, -180min }, + { 0x191B2771u, -120min }, + { 0xD7D3B14Eu, -60min }, + { 0x47CE5170u, -44min }, + { 0x350CA8AFu, 0min }, + { 0x15E8E23Bu, 60min }, + { 0x733864AEu, 120min }, + { 0xF71F9C94u, 180min }, + { 0xBDE50F54u, 210min }, + { 0x2BDD6DB9u, 240min }, + { 0xB1E07F42u, 270min }, + { 0x454FF132u, 300min }, + { 0x3F4DA929u, 330min }, + { 0xD1554AC4u, 360min }, + { 0xBB667143u, 390min }, + { 0x9E2B78C9u, 420min }, + { 0x1C377816u, 450min }, + { 0x1A4440E3u, 480min }, + { 0xB49DF789u, 525min }, + { 0xC3A28C54u, 540min }, + { 0x35A9FB8Fu, 570min }, + { 0x889BD751u, 600min }, + { 0x8CAAE827u, 660min }, + { 0x7285EE60u, 690min }, + { 0x1CC2DEF4u, 720min }, + { 0x89B8FD2Fu, 765min }, + { 0x98DBA70Eu, 780min }, + { 0xC59585BBu, 840min } + }; +#endif + + return hashToOffset; +} + +std::unordered_map<uint32, Minutes, std::identity> const _timezoneOffsetsByHash = InitTimezoneHashDb(); + +using ClientSupportedTimezone = std::pair<Minutes, std::string>; +std::array<ClientSupportedTimezone, 11> const _clientSupportedTimezones = +{{ + { -480min, "America/Los_Angeles" }, + { -420min, "America/Denver" }, + { -360min, "America/Chicago" }, + { -300min, "America/New_York" }, + { -180min, "America/Sao_Paulo" }, + { 0min, "Etc/UTC" }, + { 60min, "Europe/Paris" }, + { 480min, "Asia/Shanghai" }, + { 480min, "Asia/Taipei" }, + { 540min, "Asia/Seoul" }, + { 600min, "Australia/Melbourne" }, +}}; +} + +namespace Trinity::Timezone +{ +Minutes GetOffsetByHash(uint32 hash) +{ + if (Minutes const* offset = Containers::MapGetValuePtr(_timezoneOffsetsByHash, hash)) + return *offset; + + return 0min; +} + +Minutes GetSystemZoneOffsetAt(SystemTimePoint date) +{ + Seconds offset; +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS + offset = std::chrono::current_zone()->get_info(date).offset; +#else + tm buf = TimeBreakdown(std::chrono::system_clock::to_time_t(date)); + offset = Seconds(buf.tm_gmtoff); +#endif + return std::chrono::duration_cast<Minutes>(offset); +} + +Minutes GetSystemZoneOffset(bool applyDst /*= true*/) +{ + std::chrono::system_clock::time_point date = std::chrono::system_clock::from_time_t(std::time_t(0)); + if (applyDst) + date = std::chrono::system_clock::now(); + + return GetSystemZoneOffsetAt(date); +} + +std::string GetSystemZoneName() +{ +#if TRINITY_PLATFORM == TRINITY_PLATFORM_WINDOWS + return std::string(std::chrono::current_zone()->name()); +#else + static std::locale calendarLocale = boost::locale::generator().generate(""); + std::unique_ptr<boost::locale::abstract_calendar> p(std::use_facet<class boost::locale::calendar_facet>(calendarLocale).create_calendar()); + return p->get_timezone(); +#endif +} + +std::string_view FindClosestClientSupportedTimezone(std::string_view currentTimezone, Minutes currentTimezoneOffset) +{ + // try exact match + auto itr = std::find_if(_clientSupportedTimezones.begin(), _clientSupportedTimezones.end(), [currentTimezone](ClientSupportedTimezone const& tz) + { + return tz.second == currentTimezone; + }); + if (itr != _clientSupportedTimezones.end()) + return itr->second; + + // try closest offset + itr = std::min_element(_clientSupportedTimezones.begin(), _clientSupportedTimezones.end(), [currentTimezoneOffset](ClientSupportedTimezone const& left, ClientSupportedTimezone const& right) + { + Minutes leftDiff = left.first - currentTimezoneOffset; + Minutes rightDiff = right.first - currentTimezoneOffset; + return std::abs(leftDiff.count()) < std::abs(rightDiff.count()); + }); + + return itr->second; +} +} diff --git a/src/common/Time/Timezone.h b/src/common/Time/Timezone.h new file mode 100644 index 00000000000..769bf0c5921 --- /dev/null +++ b/src/common/Time/Timezone.h @@ -0,0 +1,37 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_TIMEZONE_H +#define TRINITYCORE_TIMEZONE_H + +#include "Define.h" +#include "Duration.h" + +namespace Trinity::Timezone +{ +TC_COMMON_API Minutes GetOffsetByHash(uint32 hash); + +// Returns the time offset that must be added to UTC time to get localtime +TC_COMMON_API Minutes GetSystemZoneOffsetAt(SystemTimePoint date); +TC_COMMON_API Minutes GetSystemZoneOffset(bool applyDst = true); + +TC_COMMON_API std::string GetSystemZoneName(); + +TC_COMMON_API std::string_view FindClosestClientSupportedTimezone(std::string_view currentTimezone, Minutes currentTimezoneOffset); +} + +#endif // TRINITYCORE_TIMEZONE_H diff --git a/src/common/Utilities/Hash.h b/src/common/Utilities/Hash.h index b63201bf07a..18f7442fb44 100644 --- a/src/common/Utilities/Hash.h +++ b/src/common/Utilities/Hash.h @@ -19,6 +19,7 @@ #define TrinityCore_Hash_h__ #include <functional> +#include <string_view> #include <utility> namespace Trinity @@ -28,6 +29,17 @@ namespace Trinity { seed ^= std::hash<T>()(val) + 0x9E3779B9 + (seed << 6) + (seed >> 2); } + + inline std::uint32_t HashFnv1a(std::string_view data) + { + std::uint32_t hash = 0x811C9DC5u; + for (char c : data) + { + hash ^= c; + hash *= 0x1000193u; + } + return hash; + } } //! Hash implementation for std::pair to allow using pairs in unordered_set or as key for unordered_map diff --git a/src/common/Utilities/Util.cpp b/src/common/Utilities/Util.cpp index ac97e724902..d852ed655a0 100644 --- a/src/common/Utilities/Util.cpp +++ b/src/common/Utilities/Util.cpp @@ -58,9 +58,20 @@ std::vector<std::string_view> Trinity::Tokenize(std::string_view str, char sep, #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) struct tm* localtime_r(time_t const* time, struct tm *result) { - localtime_s(result, time); + if (localtime_s(result, time) != 0) + return nullptr; return result; } +struct tm* gmtime_r(time_t const* time, struct tm* result) +{ + if (gmtime_s(result, time) != 0) + return nullptr; + return result; +} +time_t timegm(struct tm* tm) +{ + return _mkgmtime(tm); +} #endif tm TimeBreakdown(time_t time) @@ -70,17 +81,6 @@ tm TimeBreakdown(time_t time) return timeLocal; } -time_t LocalTimeToUTCTime(time_t time) -{ -#if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) - return time + _timezone; -#elif defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) - return timegm(gmtime(&time)); -#else - return time + timezone; -#endif -} - time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime) { tm timeLocal = TimeBreakdown(time); diff --git a/src/common/Utilities/Util.h b/src/common/Utilities/Util.h index be4a68d7788..334b3ab6ac0 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -54,8 +54,9 @@ TC_COMMON_API Optional<int64> MoneyStringToMoney(std::string const& moneyString) #if (defined(WIN32) || defined(_WIN32) || defined(__WIN32__)) TC_COMMON_API struct tm* localtime_r(time_t const* time, struct tm *result); +TC_COMMON_API struct tm* gmtime_r(time_t const* time, struct tm *result); +TC_COMMON_API time_t timegm(struct tm* tm); #endif -TC_COMMON_API time_t LocalTimeToUTCTime(time_t time); TC_COMMON_API time_t GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime = true); TC_COMMON_API tm TimeBreakdown(time_t t); diff --git a/src/server/bnetserver/Server/Session.cpp b/src/server/bnetserver/Server/Session.cpp index 6e5b16cd477..95c46418a7d 100644 --- a/src/server/bnetserver/Server/Session.cpp +++ b/src/server/bnetserver/Server/Session.cpp @@ -21,13 +21,17 @@ #include "CryptoRandom.h" #include "DatabaseEnv.h" #include "Errors.h" +#include "Hash.h" #include "IPLocation.h" -#include "QueryCallback.h" #include "LoginRESTService.h" +#include "MapUtils.h" #include "ProtobufJSON.h" +#include "QueryCallback.h" #include "RealmList.h" -#include "ServiceDispatcher.h" #include "RealmList.pb.h" +#include "ServiceDispatcher.h" +#include "Timezone.h" +#include <rapidjson/document.h> #include <zlib.h> void Battlenet::Session::AccountInfo::LoadResult(PreparedQueryResult result) @@ -229,6 +233,26 @@ uint32 Battlenet::Session::HandleLogon(authentication::v1::LogonRequest const* l _os = logonRequest->platform(); _build = logonRequest->application_version(); + _timezoneOffset = [&] + { + if (!logonRequest->has_device_id()) + return 0min; + + rapidjson::Document doc; + doc.Parse(logonRequest->device_id()); + if (doc.HasParseError()) + return 0min; + + auto itr = doc.FindMember("UTCO"); + if (itr == doc.MemberEnd()) + return 0min; + + if (!itr->value.IsUint()) + return 0min; + + return Trinity::Timezone::GetOffsetByHash(itr->value.GetUint()); + }(); + if (logonRequest->has_cached_web_credentials()) return VerifyWebCredentials(logonRequest->cached_web_credentials(), continuation); @@ -670,7 +694,8 @@ uint32 Battlenet::Session::GetRealmList(std::unordered_map<std::string, Variant uint32 Battlenet::Session::JoinRealm(std::unordered_map<std::string, Variant const*> const& params, game_utilities::v1::ClientResponse* response) { if (Variant const* realmAddress = GetParam(params, "Param_RealmAddress")) - return sRealmList->JoinRealm(realmAddress->uint_value(), _build, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), _os, _gameAccountInfo->Name, response); + return sRealmList->JoinRealm(realmAddress->uint_value(), _build, GetRemoteIpAddress(), _clientSecret, GetLocaleByName(_locale), + _os, _timezoneOffset, _gameAccountInfo->Name, response); return ERROR_WOW_SERVICES_INVALID_JOIN_TICKET; } diff --git a/src/server/bnetserver/Server/Session.h b/src/server/bnetserver/Server/Session.h index fd375b3a19a..01167d38a0b 100644 --- a/src/server/bnetserver/Server/Session.h +++ b/src/server/bnetserver/Server/Session.h @@ -19,6 +19,7 @@ #define Session_h__ #include "AsyncCallbackProcessor.h" +#include "Duration.h" #include "Realm.h" #include "SslContext.h" #include "SslSocket.h" @@ -173,6 +174,7 @@ namespace Battlenet std::string _locale; std::string _os; uint32 _build; + Minutes _timezoneOffset; std::string _ipCountry; diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 0b9fd4e8f89..5745a063e53 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -39,7 +39,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_LOGON, "UPDATE account SET salt = ?, verifier = ? WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_ACCOUNT_ID_BY_NAME, "SELECT id FROM account WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_NAME, "SELECT id, username FROM account WHERE username = ?", CONNECTION_SYNCH); - PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, ba.id, aa.SecurityLevel, " + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key_bnet, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, " "bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id " "FROM account a LEFT JOIN account r ON a.id = r.recruiter LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id " "LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 " @@ -129,7 +129,7 @@ void LoginDatabaseConnection::DoPrepareStatements() " FROM battlenet_accounts ba LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account a ON ba.id = a.battlenet_account" " LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID = -1 WHERE ba.LoginTicket = ? ORDER BY a.id", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_BNET_LAST_LOGIN_INFO, "UPDATE battlenet_accounts SET last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET session_key_bnet = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO, "UPDATE account SET session_key_bnet = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ?, timezone_offset = ? WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_ACCOUNT_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id WHERE rc.acctid = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_CHARACTER_COUNTS_BY_BNET_ID, "SELECT rc.acctid, rc.numchars, r.id, r.Region, r.Battlegroup FROM realmcharacters rc INNER JOIN realmlist r ON rc.realmid = r.id LEFT JOIN account a ON rc.acctid = a.id WHERE a.battlenet_account = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_BNET_LAST_PLAYER_CHARACTERS, "SELECT lpc.accountId, lpc.region, lpc.battlegroup, lpc.realmId, lpc.characterName, lpc.characterGUID, lpc.lastPlayedTime FROM account_last_played_character lpc LEFT JOIN account a ON lpc.accountId = a.id WHERE a.battlenet_account = ?", CONNECTION_ASYNC); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 46891c35031..a2b401215f2 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -370,42 +370,42 @@ void PlayerAchievementMgr::SendAllData(Player const* /*receiver*/) const if (!achievement) continue; - WorldPackets::Achievement::EarnedAchievement earned; + WorldPackets::Achievement::EarnedAchievement& earned = achievementData.Data.Earned.emplace_back(); earned.Id = completedAchievement.first; - earned.Date = completedAchievement.second.Date; + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.second.Date); + earned.Date += _owner->GetSession()->GetTimezoneOffset(); if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) { earned.Owner = _owner->GetGUID(); earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); } - achievementData.Data.Earned.push_back(earned); } for (std::pair<uint32 const, CriteriaProgress> const& criteriaProgres : _criteriaProgress) { Criteria const* criteria = sCriteriaMgr->GetCriteria(criteriaProgres.first); - WorldPackets::Achievement::CriteriaProgress progress; + WorldPackets::Achievement::CriteriaProgress& progress = achievementData.Data.Progress.emplace_back(); progress.Id = criteriaProgres.first; progress.Quantity = criteriaProgres.second.Counter; progress.Player = criteriaProgres.second.PlayerGUID; progress.Flags = 0; - progress.Date = criteriaProgres.second.Date; + progress.Date.SetUtcTimeFromUnixTime(criteriaProgres.second.Date); + progress.Date += _owner->GetSession()->GetTimezoneOffset(); progress.TimeFromStart = Seconds::zero(); progress.TimeFromCreate = Seconds::zero(); - achievementData.Data.Progress.push_back(progress); if (criteria->FlagsCu & CRITERIA_FLAG_CU_ACCOUNT) { - WorldPackets::Achievement::CriteriaProgress progress; - progress.Id = criteriaProgres.first; - progress.Quantity = criteriaProgres.second.Counter; - progress.Player = _owner->GetSession()->GetBattlenetAccountGUID(); - progress.Flags = 0; - progress.Date = criteriaProgres.second.Date; - progress.TimeFromStart = Seconds::zero(); - progress.TimeFromCreate = Seconds::zero(); - allAccountCriteria.Progress.push_back(progress); + WorldPackets::Achievement::CriteriaProgress& accountProgress = allAccountCriteria.Progress.emplace_back(); + accountProgress.Id = criteriaProgres.first; + accountProgress.Quantity = criteriaProgres.second.Counter; + accountProgress.Player = _owner->GetSession()->GetBattlenetAccountGUID(); + accountProgress.Flags = 0; + accountProgress.Date.SetUtcTimeFromUnixTime(criteriaProgres.second.Date); + accountProgress.Date += _owner->GetSession()->GetTimezoneOffset(); + accountProgress.TimeFromStart = Seconds::zero(); + accountProgress.TimeFromCreate = Seconds::zero(); } } @@ -429,28 +429,28 @@ void PlayerAchievementMgr::SendAchievementInfo(Player* receiver, uint32 /*achiev if (!achievement) continue; - WorldPackets::Achievement::EarnedAchievement earned; + WorldPackets::Achievement::EarnedAchievement& earned = inspectedAchievements.Data.Earned.emplace_back(); earned.Id = completedAchievement.first; - earned.Date = completedAchievement.second.Date; + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.second.Date); + earned.Date += receiver->GetSession()->GetTimezoneOffset(); if (!(achievement->Flags & ACHIEVEMENT_FLAG_ACCOUNT)) { earned.Owner = _owner->GetGUID(); earned.VirtualRealmAddress = earned.NativeRealmAddress = GetVirtualRealmAddress(); } - inspectedAchievements.Data.Earned.push_back(earned); } for (std::pair<uint32 const, CriteriaProgress> const& criteriaProgres : _criteriaProgress) { - WorldPackets::Achievement::CriteriaProgress progress; + WorldPackets::Achievement::CriteriaProgress& progress = inspectedAchievements.Data.Progress.emplace_back(); progress.Id = criteriaProgres.first; progress.Quantity = criteriaProgres.second.Counter; progress.Player = criteriaProgres.second.PlayerGUID; progress.Flags = 0; - progress.Date = criteriaProgres.second.Date; + progress.Date.SetUtcTimeFromUnixTime(criteriaProgres.second.Date); + progress.Date += receiver->GetSession()->GetTimezoneOffset(); progress.TimeFromStart = Seconds::zero(); progress.TimeFromCreate = Seconds::zero(); - inspectedAchievements.Data.Progress.push_back(progress); } receiver->SendDirectMessage(inspectedAchievements.Write()); @@ -571,7 +571,8 @@ void PlayerAchievementMgr::SendCriteriaUpdate(Criteria const* criteria, Criteria if (criteria->Entry->StartTimer) criteriaUpdate.Progress.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client - criteriaUpdate.Progress.Date = progress->Date; + criteriaUpdate.Progress.Date.SetUtcTimeFromUnixTime(progress->Date); + criteriaUpdate.Progress.Date += _owner->GetSession()->GetTimezoneOffset(); criteriaUpdate.Progress.TimeFromStart = timeElapsed; criteriaUpdate.Progress.TimeFromCreate = Seconds::zero(); @@ -588,7 +589,8 @@ void PlayerAchievementMgr::SendCriteriaUpdate(Criteria const* criteria, Criteria if (criteria->Entry->StartTimer) criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client - criteriaUpdate.CurrentTime = progress->Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(progress->Date); + criteriaUpdate.CurrentTime += _owner->GetSession()->GetTimezoneOffset(); criteriaUpdate.ElapsedTime = timeElapsed; criteriaUpdate.CreationTime = 0; @@ -639,16 +641,26 @@ void PlayerAchievementMgr::SendAchievementEarned(AchievementEntry const* achieve } } - WorldPackets::Achievement::AchievementEarned achievementEarned; - achievementEarned.Sender = _owner->GetGUID(); - achievementEarned.Earner = _owner->GetGUID(); - achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = GetVirtualRealmAddress(); - achievementEarned.AchievementID = achievement->ID; - achievementEarned.Time = GameTime::GetGameTime(); + auto achievementEarnedBuilder = [&](Player const* receiver) + { + WorldPackets::Achievement::AchievementEarned achievementEarned; + achievementEarned.Sender = _owner->GetGUID(); + achievementEarned.Earner = _owner->GetGUID(); + achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = GetVirtualRealmAddress(); + achievementEarned.AchievementID = achievement->ID; + achievementEarned.Time = *GameTime::GetUtcWowTime(); + achievementEarned.Time += receiver->GetSession()->GetTimezoneOffset(); + receiver->SendDirectMessage(achievementEarned.Write()); + }; + if (!(achievement->Flags & ACHIEVEMENT_FLAG_TRACKING_FLAG)) - _owner->SendMessageToSetInRange(achievementEarned.Write(), sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + { + float dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY); + Trinity::MessageDistDeliverer notifier(_owner, achievementEarnedBuilder, dist); + Cell::VisitWorldObjects(_owner, notifier, dist); + } else - _owner->SendDirectMessage(achievementEarned.Write()); + achievementEarnedBuilder(_owner); } void PlayerAchievementMgr::SendPacket(WorldPacket const* data) const @@ -672,11 +684,16 @@ void GuildAchievementMgr::Reset() ObjectGuid guid = _owner->GetGUID(); for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : _completedAchievements) { - WorldPackets::Achievement::GuildAchievementDeleted guildAchievementDeleted; - guildAchievementDeleted.AchievementID = completedAchievement.first; - guildAchievementDeleted.GuildGUID = guid; - guildAchievementDeleted.TimeDeleted = GameTime::GetGameTime(); - SendPacket(guildAchievementDeleted.Write()); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Achievement::GuildAchievementDeleted guildAchievementDeleted; + guildAchievementDeleted.AchievementID = completedAchievement.first; + guildAchievementDeleted.GuildGUID = guid; + guildAchievementDeleted.TimeDeleted = *GameTime::GetUtcWowTime(); + guildAchievementDeleted.TimeDeleted += receiver->GetSession()->GetTimezoneOffset(); + receiver->SendDirectMessage(guildAchievementDeleted.Write()); + }; + _owner->BroadcastWorker(packetBuilder); } _achievementPoints = 0; @@ -823,10 +840,10 @@ void GuildAchievementMgr::SendAllData(Player const* receiver) const if (!achievement) continue; - WorldPackets::Achievement::EarnedAchievement earned; + WorldPackets::Achievement::EarnedAchievement& earned = allGuildAchievements.Earned.emplace_back(); earned.Id = completedAchievement.first; - earned.Date = completedAchievement.second.Date; - allGuildAchievements.Earned.push_back(earned); + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.second.Date); + earned.Date += receiver->GetSession()->GetTimezoneOffset(); } receiver->SendDirectMessage(allGuildAchievements.Write()); @@ -839,23 +856,22 @@ void GuildAchievementMgr::SendAchievementInfo(Player* receiver, uint32 achieveme { if (CriteriaTree const* tree = sCriteriaMgr->GetCriteriaTree(achievement->CriteriaTree)) { - CriteriaMgr::WalkCriteriaTree(tree, [this, &guildCriteriaUpdate](CriteriaTree const* node) + CriteriaMgr::WalkCriteriaTree(tree, [this, &guildCriteriaUpdate, receiver](CriteriaTree const* node) { if (node->Criteria) { auto progress = this->_criteriaProgress.find(node->Criteria->ID); if (progress != this->_criteriaProgress.end()) { - WorldPackets::Achievement::GuildCriteriaProgress guildCriteriaProgress; + WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress.emplace_back(); guildCriteriaProgress.CriteriaID = node->Criteria->ID; guildCriteriaProgress.DateCreated = 0; guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->second.Date; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress->second.Date); + guildCriteriaProgress.DateUpdated += receiver->GetSession()->GetTimezoneOffset(); guildCriteriaProgress.Quantity = progress->second.Counter; guildCriteriaProgress.PlayerGUID = progress->second.PlayerGUID; guildCriteriaProgress.Flags = 0; - - guildCriteriaUpdate.Progress.push_back(guildCriteriaProgress); } } }); @@ -876,16 +892,15 @@ void GuildAchievementMgr::SendAllTrackedCriterias(Player* receiver, std::set<uin if (progress == _criteriaProgress.end()) continue; - WorldPackets::Achievement::GuildCriteriaProgress guildCriteriaProgress; + WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress.emplace_back(); guildCriteriaProgress.CriteriaID = criteriaId; guildCriteriaProgress.DateCreated = 0; guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->second.Date; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress->second.Date); + guildCriteriaProgress.DateUpdated += receiver->GetSession()->GetTimezoneOffset(); guildCriteriaProgress.Quantity = progress->second.Counter; guildCriteriaProgress.PlayerGUID = progress->second.PlayerGUID; guildCriteriaProgress.Flags = 0; - - guildCriteriaUpdate.Progress.push_back(guildCriteriaProgress); } receiver->SendDirectMessage(guildCriteriaUpdate.Write()); @@ -949,19 +964,21 @@ void GuildAchievementMgr::CompletedAchievement(AchievementEntry const* achieveme void GuildAchievementMgr::SendCriteriaUpdate(Criteria const* entry, CriteriaProgress const* progress, Seconds /*timeElapsed*/, bool /*timedCompleted*/) const { - WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; - guildCriteriaUpdate.Progress.resize(1); - - WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress[0]; - guildCriteriaProgress.CriteriaID = entry->ID; - guildCriteriaProgress.DateCreated = 0; - guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress->Date; - guildCriteriaProgress.Quantity = progress->Counter; - guildCriteriaProgress.PlayerGUID = progress->PlayerGUID; - guildCriteriaProgress.Flags = 0; - - _owner->BroadcastPacketIfTrackingAchievement(guildCriteriaUpdate.Write(), entry->ID); + for (Player const* member : _owner->GetMembersTrackingCriteria(entry->ID)) + { + WorldPackets::Achievement::GuildCriteriaUpdate guildCriteriaUpdate; + WorldPackets::Achievement::GuildCriteriaProgress& guildCriteriaProgress = guildCriteriaUpdate.Progress.emplace_back(); + guildCriteriaProgress.CriteriaID = entry->ID; + guildCriteriaProgress.DateCreated = 0; + guildCriteriaProgress.DateStarted = 0; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress->Date); + guildCriteriaProgress.DateUpdated += member->GetSession()->GetTimezoneOffset(); + guildCriteriaProgress.Quantity = progress->Counter; + guildCriteriaProgress.PlayerGUID = progress->PlayerGUID; + guildCriteriaProgress.Flags = 0; + + member->SendDirectMessage(guildCriteriaUpdate.Write()); + } } void GuildAchievementMgr::SendCriteriaProgressRemoved(uint32 criteriaId) @@ -985,11 +1002,16 @@ void GuildAchievementMgr::SendAchievementEarned(AchievementEntry const* achievem sWorld->SendGlobalMessage(serverFirstAchievement.Write()); } - WorldPackets::Achievement::GuildAchievementEarned guildAchievementEarned; - guildAchievementEarned.AchievementID = achievement->ID; - guildAchievementEarned.GuildGUID = _owner->GetGUID(); - guildAchievementEarned.TimeEarned = GameTime::GetGameTime(); - SendPacket(guildAchievementEarned.Write()); + auto guildAchievementEarnedBuilder = [&](Player const* receiver) + { + WorldPackets::Achievement::GuildAchievementEarned guildAchievementEarned; + guildAchievementEarned.AchievementID = achievement->ID; + guildAchievementEarned.GuildGUID = _owner->GetGUID(); + guildAchievementEarned.TimeEarned = *GameTime::GetUtcWowTime(); + guildAchievementEarned.TimeEarned += receiver->GetSession()->GetTimezoneOffset(); + receiver->SendDirectMessage(guildAchievementEarned.Write()); + }; + _owner->BroadcastWorker(guildAchievementEarnedBuilder); } void GuildAchievementMgr::SendPacket(WorldPacket const* data) const diff --git a/src/server/game/Achievements/CriteriaHandler.cpp b/src/server/game/Achievements/CriteriaHandler.cpp index a821b11c642..8d9a54c8789 100644 --- a/src/server/game/Achievements/CriteriaHandler.cpp +++ b/src/server/game/Achievements/CriteriaHandler.cpp @@ -49,6 +49,7 @@ #include "World.h" #include "WorldSession.h" #include "WorldStateMgr.h" +#include "WowTime.h" bool CriteriaData::IsValid(Criteria const* criteria) { @@ -2230,14 +2231,12 @@ bool CriteriaHandler::ModifierSatisfied(ModifierTreeEntry const* modifier, uint6 break; case ModifierTreeType::TimeBetween: // 109 { - ByteBuffer unpacker; - unpacker << reqValue; - time_t from = unpacker.ReadPackedTime(); - unpacker.rpos(0); - unpacker.wpos(0); - unpacker << secondaryAsset; - time_t to = unpacker.ReadPackedTime(); - if (GameTime::GetGameTime() < from || GameTime::GetGameTime() > to) + WowTime from; + from.SetPackedTime(reqValue); + WowTime to; + to.SetPackedTime(secondaryAsset); + + if (!GameTime::GetWowTime()->IsInRange(from, to)) return false; break; } diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index 0d149078279..21332e20171 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -34,11 +34,11 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" -#include "Realm.h" #include "ScriptMgr.h" +#include "Timezone.h" #include "World.h" -#include "WorldPacket.h" #include "WorldSession.h" +#include "WowTime.h" #include <boost/dynamic_bitset.hpp> #include <numeric> #include <sstream> @@ -1911,13 +1911,13 @@ void AuctionHouseObject::SendAuctionInvoice(AuctionPosting const* auction, Playe // owner exist (online or offline) if ((owner || sCharacterCache->HasCharacterCacheEntry(auction->Owner)) && !sAuctionBotConfig->IsBotChar(auction->Owner)) { - ByteBuffer tempBuffer; - tempBuffer.AppendPackedTime(GameTime::GetGameTime() + sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY)); - uint32 eta = tempBuffer.read<uint32>(); + WowTime eta = *GameTime::GetUtcWowTime(); + eta += Seconds(sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY)); + eta += owner->GetSession()->GetTimezoneOffset(); MailDraft(AuctionHouseMgr::BuildItemAuctionMailSubject(AuctionMailType::Invoice, auction), AuctionHouseMgr::BuildAuctionInvoiceMailBody(auction->Bidder, auction->BidAmount, auction->BuyoutOrUnitPrice, auction->Deposit, - CalculateAuctionHouseCut(auction->BidAmount), sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), eta)) + CalculateAuctionHouseCut(auction->BidAmount), sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), eta.GetPackedTime())) .SendMailTo(trans, MailReceiver(owner, auction->Owner), this, MAIL_CHECK_MASK_COPIED); } } diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index fdceaa3762e..66f8ab9cb27 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -24,12 +24,16 @@ #include "GuildMgr.h" #include "Log.h" #include "Mail.h" +#include "MapUtils.h" #include "ObjectAccessor.h" #include "Player.h" +#include "StringConvert.h" +#include "WorldSession.h" +#include "WowTime.h" #include <sstream> CalendarInvite::CalendarInvite() : _inviteId(1), _eventId(0), _invitee(), _senderGUID(), _responseTime(0), -_status(CALENDAR_STATUS_INVITED), _rank(CALENDAR_RANK_PLAYER), _note("") { } +_status(CALENDAR_STATUS_INVITED), _rank(CALENDAR_RANK_PLAYER), _note() { } CalendarInvite::~CalendarInvite() { @@ -184,7 +188,6 @@ void CalendarMgr::RemoveEvent(CalendarEvent* calendarEvent, ObjectGuid remover) CharacterDatabaseTransaction trans = CharacterDatabase.BeginTransaction(); CharacterDatabasePreparedStatement* stmt; - MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody()); CalendarInviteStore& eventInvites = _invites[calendarEvent->GetEventId()]; for (size_t i = 0; i < eventInvites.size(); ++i) @@ -197,7 +200,10 @@ void CalendarMgr::RemoveEvent(CalendarEvent* calendarEvent, ObjectGuid remover) // guild events only? check invite status here? // When an event is deleted, all invited (accepted/declined? - verify) guildies are notified via in-game mail. (wowwiki) if (!remover.IsEmpty() && invite->GetInviteeGUID() != remover) + { + MailDraft mail(calendarEvent->BuildCalendarMailSubject(remover), calendarEvent->BuildCalendarMailBody(ObjectAccessor::FindConnectedPlayer(invite->GetInviteeGUID()))); mail.SendMailTo(trans, MailReceiver(invite->GetInviteeGUID().GetCounter()), calendarEvent, MAIL_CHECK_MASK_COPIED); + } delete invite; } @@ -375,7 +381,7 @@ void CalendarMgr::DeleteOldEvents() } } -CalendarEventStore CalendarMgr::GetEventsCreatedBy(ObjectGuid guid, bool includeGuildEvents) +CalendarEventStore CalendarMgr::GetEventsCreatedBy(ObjectGuid guid, bool includeGuildEvents) const { CalendarEventStore result; for (CalendarEventStore::const_iterator itr = _events.begin(); itr != _events.end(); ++itr) @@ -385,7 +391,7 @@ CalendarEventStore CalendarMgr::GetEventsCreatedBy(ObjectGuid guid, bool include return result; } -CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) +CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) const { CalendarEventStore result; @@ -400,7 +406,7 @@ CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) return result; } -CalendarEventStore CalendarMgr::GetPlayerEvents(ObjectGuid guid) +CalendarEventStore CalendarMgr::GetPlayerEvents(ObjectGuid guid) const { CalendarEventStore events; @@ -419,12 +425,16 @@ CalendarEventStore CalendarMgr::GetPlayerEvents(ObjectGuid guid) return events; } -CalendarInviteStore const& CalendarMgr::GetEventInvites(uint64 eventId) +CalendarInviteStore CalendarMgr::GetEventInvites(uint64 eventId) const { - return _invites[eventId]; + CalendarInviteStore invites; + if (CalendarInviteStore const* invitesStore = Trinity::Containers::MapGetValuePtr(_invites, eventId)) + invites = *invitesStore; + + return invites; } -CalendarInviteStore CalendarMgr::GetPlayerInvites(ObjectGuid guid) +CalendarInviteStore CalendarMgr::GetPlayerInvites(ObjectGuid guid) const { CalendarInviteStore invites; @@ -465,20 +475,17 @@ std::string CalendarEvent::BuildCalendarMailSubject(ObjectGuid remover) const return strm.str(); } -std::string CalendarEvent::BuildCalendarMailBody() const +std::string CalendarEvent::BuildCalendarMailBody(Player const* invitee) const { - WorldPacket data; - uint32 time; - std::ostringstream strm; + WowTime time; + time.SetUtcTimeFromUnixTime(_date); + if (invitee) + time += invitee->GetSession()->GetTimezoneOffset(); - // we are supposed to send PackedTime so i used WorldPacket to pack it - data.AppendPackedTime(_date); - data >> time; - strm << time; - return strm.str(); + return Trinity::ToString(time.GetPackedTime()); } -void CalendarMgr::SendCalendarEventInvite(CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventInvite(CalendarInvite const& invite) const { CalendarEvent* calendarEvent = GetEvent(invite.GetEventId()); @@ -487,71 +494,103 @@ void CalendarMgr::SendCalendarEventInvite(CalendarInvite const& invite) uint8 level = player ? player->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(invitee); - WorldPackets::Calendar::CalendarInviteAdded packet; - packet.EventID = calendarEvent ? calendarEvent->GetEventId() : 0; - packet.InviteGuid = invitee; - packet.InviteID = calendarEvent ? invite.GetInviteId() : 0; - packet.Level = level; - packet.ResponseTime = invite.GetResponseTime(); - packet.Status = invite.GetStatus(); - packet.Type = calendarEvent ? calendarEvent->IsGuildEvent() : 0; // Correct ? - packet.ClearPending = calendarEvent ? !calendarEvent->IsGuildEvent() : true; // Correct ? + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarInviteAdded packet; + packet.EventID = calendarEvent ? calendarEvent->GetEventId() : 0; + packet.InviteGuid = invitee; + packet.InviteID = calendarEvent ? invite.GetInviteId() : 0; + packet.Level = level; + packet.ResponseTime.SetUtcTimeFromUnixTime(invite.GetResponseTime()); + packet.ResponseTime += receiver->GetSession()->GetTimezoneOffset(); + packet.Status = invite.GetStatus(); + packet.Type = calendarEvent ? calendarEvent->IsGuildEvent() : 0; // Correct ? + packet.ClearPending = calendarEvent ? !calendarEvent->IsGuildEvent() : true; // Correct ? + + receiver->SendDirectMessage(packet.Write()); + }; if (!calendarEvent) // Pre-invite { if (Player* playerSender = ObjectAccessor::FindConnectedPlayer(invite.GetSenderGUID())) - playerSender->SendDirectMessage(packet.Write()); + packetBuilder(playerSender); } else { if (calendarEvent->GetOwnerGUID() != invite.GetInviteeGUID()) // correct? - SendPacketToAllEventRelatives(packet.Write(), *calendarEvent); + for (Player* receiver : GetAllEventRelatives(*calendarEvent)) + packetBuilder(receiver); } } -void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t originalDate) +void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t originalDate) const { - WorldPackets::Calendar::CalendarEventUpdatedAlert packet; - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.GetDate(); - packet.Description = calendarEvent.GetDescription(); - packet.EventClubID = calendarEvent.GetGuildId(); - packet.EventID = calendarEvent.GetEventId(); - packet.EventName = calendarEvent.GetTitle(); - packet.EventType = calendarEvent.GetType(); - packet.Flags = calendarEvent.GetFlags(); - packet.LockDate = calendarEvent.GetLockDate(); // Always 0 ? - packet.OriginalDate = originalDate; - packet.TextureID = calendarEvent.GetTextureId(); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarEventUpdatedAlert packet; + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.Description = calendarEvent.GetDescription(); + packet.EventClubID = calendarEvent.GetGuildId(); + packet.EventID = calendarEvent.GetEventId(); + packet.EventName = calendarEvent.GetTitle(); + packet.EventType = calendarEvent.GetType(); + packet.Flags = calendarEvent.GetFlags(); + packet.LockDate.SetUtcTimeFromUnixTime(calendarEvent.GetLockDate()); // Always 0 ? + if (calendarEvent.GetLockDate()) + packet.LockDate += receiver->GetSession()->GetTimezoneOffset(); + packet.OriginalDate.SetUtcTimeFromUnixTime(originalDate); + packet.OriginalDate += receiver->GetSession()->GetTimezoneOffset(); + packet.TextureID = calendarEvent.GetTextureId(); - SendPacketToAllEventRelatives(packet.Write(), calendarEvent); + receiver->SendDirectMessage(packet.Write()); + }; + + for (Player* receiver : GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } -void CalendarMgr::SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const { - WorldPackets::Calendar::CalendarInviteStatus packet; - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.GetDate(); - packet.EventID = calendarEvent.GetEventId(); - packet.Flags = calendarEvent.GetFlags(); - packet.InviteGuid = invite.GetInviteeGUID(); - packet.ResponseTime = invite.GetResponseTime(); - packet.Status = invite.GetStatus(); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarInviteStatus packet; + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.EventID = calendarEvent.GetEventId(); + packet.Flags = calendarEvent.GetFlags(); + packet.InviteGuid = invite.GetInviteeGUID(); + packet.ResponseTime.SetUtcTimeFromUnixTime(invite.GetResponseTime()); + packet.ResponseTime += receiver->GetSession()->GetTimezoneOffset(); + packet.Status = invite.GetStatus(); - SendPacketToAllEventRelatives(packet.Write(), calendarEvent); + receiver->SendDirectMessage(packet.Write()); + }; + + for (Player* receiver : GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } -void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent) +void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent) const { - WorldPackets::Calendar::CalendarEventRemovedAlert packet; - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.GetDate(); - packet.EventID = calendarEvent.GetEventId(); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarEventRemovedAlert packet; + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.EventID = calendarEvent.GetEventId(); - SendPacketToAllEventRelatives(packet.Write(), calendarEvent); + receiver->SendDirectMessage(packet.Write()); + }; + + for (Player* receiver : GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } -void CalendarMgr::SendCalendarEventInviteRemove(CalendarEvent const& calendarEvent, CalendarInvite const& invite, uint32 flags) +void CalendarMgr::SendCalendarEventInviteRemove(CalendarEvent const& calendarEvent, CalendarInvite const& invite, uint32 flags) const { WorldPackets::Calendar::CalendarInviteRemoved packet; packet.ClearPending = true; // FIXME @@ -562,7 +601,7 @@ void CalendarMgr::SendCalendarEventInviteRemove(CalendarEvent const& calendarEve SendPacketToAllEventRelatives(packet.Write(), calendarEvent); } -void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const { WorldPackets::Calendar::CalendarModeratorStatus packet; packet.ClearPending = true; // FIXME @@ -573,82 +612,94 @@ void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& cal SendPacketToAllEventRelatives(packet.Write(), calendarEvent); } -void CalendarMgr::SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const { - WorldPackets::Calendar::CalendarInviteAlert packet; - packet.Date = calendarEvent.GetDate(); - packet.EventID = calendarEvent.GetEventId(); - packet.EventName = calendarEvent.GetTitle(); - packet.EventType = calendarEvent.GetType(); - packet.Flags = calendarEvent.GetFlags(); - packet.InviteID = invite.GetInviteId(); - packet.InvitedByGuid = invite.GetSenderGUID(); - packet.ModeratorStatus = invite.GetRank(); - packet.OwnerGuid = calendarEvent.GetOwnerGUID(); - packet.Status = invite.GetStatus(); - packet.TextureID = calendarEvent.GetTextureId(); - packet.EventClubID = calendarEvent.GetGuildId(); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarInviteAlert packet; + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.EventID = calendarEvent.GetEventId(); + packet.EventName = calendarEvent.GetTitle(); + packet.EventType = calendarEvent.GetType(); + packet.Flags = calendarEvent.GetFlags(); + packet.InviteID = invite.GetInviteId(); + packet.InvitedByGuid = invite.GetSenderGUID(); + packet.ModeratorStatus = invite.GetRank(); + packet.OwnerGuid = calendarEvent.GetOwnerGUID(); + packet.Status = invite.GetStatus(); + packet.TextureID = calendarEvent.GetTextureId(); + packet.EventClubID = calendarEvent.GetGuildId(); + + receiver->SendDirectMessage(packet.Write()); + }; if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) { if (Guild* guild = sGuildMgr->GetGuildById(calendarEvent.GetGuildId())) - guild->BroadcastPacket(packet.Write()); + guild->BroadcastWorker(packetBuilder); } else if (Player* player = ObjectAccessor::FindConnectedPlayer(invite.GetInviteeGUID())) - player->SendDirectMessage(packet.Write()); + packetBuilder(player); } -void CalendarMgr::SendCalendarEvent(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarSendEventType sendType) +void CalendarMgr::SendCalendarEvent(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarSendEventType sendType) const { Player* player = ObjectAccessor::FindConnectedPlayer(guid); if (!player) return; - CalendarInviteStore const& eventInviteeList = _invites[calendarEvent.GetEventId()]; - WorldPackets::Calendar::CalendarSendEvent packet; - packet.Date = calendarEvent.GetDate(); + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += player->GetSession()->GetTimezoneOffset(); packet.Description = calendarEvent.GetDescription(); packet.EventID = calendarEvent.GetEventId(); packet.EventName = calendarEvent.GetTitle(); packet.EventType = sendType; packet.Flags = calendarEvent.GetFlags(); packet.GetEventType = calendarEvent.GetType(); - packet.LockDate = calendarEvent.GetLockDate(); // Always 0 ? + packet.LockDate.SetUtcTimeFromUnixTime(calendarEvent.GetLockDate()); // Always 0 ? + if (calendarEvent.GetLockDate()) + packet.LockDate += player->GetSession()->GetTimezoneOffset(); packet.OwnerGuid = calendarEvent.GetOwnerGUID(); packet.TextureID = calendarEvent.GetTextureId(); packet.EventClubID = calendarEvent.GetGuildId(); - for (auto const& calendarInvite : eventInviteeList) + if (CalendarInviteStore const* eventInviteeList = Trinity::Containers::MapGetValuePtr(_invites, calendarEvent.GetEventId())) { - ObjectGuid inviteeGuid = calendarInvite->GetInviteeGUID(); - Player* invitee = ObjectAccessor::FindPlayer(inviteeGuid); - - uint8 inviteeLevel = invitee ? invitee->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(inviteeGuid); - ObjectGuid::LowType inviteeGuildId = invitee ? invitee->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(inviteeGuid); - - WorldPackets::Calendar::CalendarEventInviteInfo inviteInfo; - inviteInfo.Guid = inviteeGuid; - inviteInfo.Level = inviteeLevel; - inviteInfo.Status = calendarInvite->GetStatus(); - inviteInfo.Moderator = calendarInvite->GetRank(); - inviteInfo.InviteType = calendarEvent.IsGuildEvent() && calendarEvent.GetGuildId() == inviteeGuildId; - inviteInfo.InviteID = calendarInvite->GetInviteId(); - inviteInfo.ResponseTime = calendarInvite->GetResponseTime(); - inviteInfo.Notes = calendarInvite->GetNote(); - - packet.Invites.push_back(inviteInfo); + for (CalendarInvite const* calendarInvite : *eventInviteeList) + { + ObjectGuid inviteeGuid = calendarInvite->GetInviteeGUID(); + Player* invitee = ObjectAccessor::FindPlayer(inviteeGuid); + + uint8 inviteeLevel = invitee ? invitee->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(inviteeGuid); + ObjectGuid::LowType inviteeGuildId = invitee ? invitee->GetGuildId() : sCharacterCache->GetCharacterGuildIdByGuid(inviteeGuid); + + WorldPackets::Calendar::CalendarEventInviteInfo inviteInfo; + inviteInfo.Guid = inviteeGuid; + inviteInfo.Level = inviteeLevel; + inviteInfo.Status = calendarInvite->GetStatus(); + inviteInfo.Moderator = calendarInvite->GetRank(); + inviteInfo.InviteType = calendarEvent.IsGuildEvent() && calendarEvent.GetGuildId() == inviteeGuildId; + inviteInfo.InviteID = calendarInvite->GetInviteId(); + inviteInfo.ResponseTime.SetUtcTimeFromUnixTime(calendarInvite->GetResponseTime()); + inviteInfo.ResponseTime += player->GetSession()->GetTimezoneOffset(); + inviteInfo.Notes = calendarInvite->GetNote(); + + packet.Invites.push_back(inviteInfo); + } } player->SendDirectMessage(packet.Write()); } -void CalendarMgr::SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarInviteStatus status) +void CalendarMgr::SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarInviteStatus status) const { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) { WorldPackets::Calendar::CalendarInviteRemovedAlert packet; - packet.Date = calendarEvent.GetDate(); + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += player->GetSession()->GetTimezoneOffset(); packet.EventID = calendarEvent.GetEventId(); packet.Flags = calendarEvent.GetFlags(); packet.Status = status; @@ -657,13 +708,13 @@ void CalendarMgr::SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEv } } -void CalendarMgr::SendCalendarClearPendingAction(ObjectGuid guid) +void CalendarMgr::SendCalendarClearPendingAction(ObjectGuid guid) const { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) player->SendDirectMessage(WorldPackets::Calendar::CalendarClearPendingAction().Write()); } -void CalendarMgr::SendCalendarCommandResult(ObjectGuid guid, CalendarError err, char const* param /*= nullptr*/) +void CalendarMgr::SendCalendarCommandResult(ObjectGuid guid, CalendarError err, char const* param /*= nullptr*/) const { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) { @@ -686,17 +737,35 @@ void CalendarMgr::SendCalendarCommandResult(ObjectGuid guid, CalendarError err, } } -void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket const* packet, CalendarEvent const& calendarEvent) +void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket const* packet, CalendarEvent const& calendarEvent) const { + for (Player* player : GetAllEventRelatives(calendarEvent)) + player->SendDirectMessage(packet); +} + +std::vector<Player*> CalendarMgr::GetAllEventRelatives(CalendarEvent const& calendarEvent) const +{ + std::vector<Player*> relatedPlayers; + // Send packet to all guild members if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) + { if (Guild* guild = sGuildMgr->GetGuildById(calendarEvent.GetGuildId())) - guild->BroadcastPacket(packet); + { + auto memberCollector = [&](Player* player) { relatedPlayers.push_back(player); }; + guild->BroadcastWorker(memberCollector); + } + } // Send packet to all invitees if event is non-guild, in other case only to non-guild invitees (packet was broadcasted for them) - CalendarInviteStore invites = _invites[calendarEvent.GetEventId()]; - for (CalendarInviteStore::iterator itr = invites.begin(); itr != invites.end(); ++itr) - if (Player* player = ObjectAccessor::FindConnectedPlayer((*itr)->GetInviteeGUID())) - if (!calendarEvent.IsGuildEvent() || player->GetGuildId() != calendarEvent.GetGuildId()) - player->SendDirectMessage(packet); + if (auto itr =_invites.find(calendarEvent.GetEventId()); itr != _invites.end()) + { + CalendarInviteStore invites = itr->second; + for (CalendarInvite const* invite : invites) + if (Player* player = ObjectAccessor::FindConnectedPlayer(invite->GetInviteeGUID())) + if (!calendarEvent.IsGuildEvent() || player->GetGuildId() != calendarEvent.GetGuildId()) + relatedPlayers.push_back(player); + } + + return relatedPlayers; } diff --git a/src/server/game/Calendar/CalendarMgr.h b/src/server/game/Calendar/CalendarMgr.h index e9119fc510f..7f0a33be1bc 100644 --- a/src/server/game/Calendar/CalendarMgr.h +++ b/src/server/game/Calendar/CalendarMgr.h @@ -26,6 +26,7 @@ #include <set> #include <vector> +class Player; class WorldPacket; enum CalendarMailAnswers @@ -159,7 +160,13 @@ struct TC_GAME_API CalendarInvite CalendarInvite(uint64 inviteId, uint64 eventId, ObjectGuid invitee, ObjectGuid senderGUID, time_t responseTime, CalendarInviteStatus status, CalendarModerationRank rank, std::string note) : _inviteId(inviteId), _eventId(eventId), _invitee(invitee), _senderGUID(senderGUID), _responseTime(responseTime), - _status(status), _rank(rank), _note(note) { } + _status(status), _rank(rank), _note(std::move(note)) { } + + CalendarInvite(CalendarInvite const&) = delete; + CalendarInvite(CalendarInvite&&) = delete; + + CalendarInvite& operator=(CalendarInvite const&) = delete; + CalendarInvite& operator=(CalendarInvite&&) = delete; ~CalendarInvite(); @@ -218,10 +225,16 @@ struct TC_GAME_API CalendarEvent CalendarEvent(uint64 eventId, ObjectGuid ownerGUID, ObjectGuid::LowType guildId, CalendarEventType type, int32 textureId, time_t date, uint32 flags, std::string title, std::string description, time_t lockDate) : _eventId(eventId), _ownerGUID(ownerGUID), _eventGuildId(guildId), _eventType(type), _textureId(textureId), - _date(date), _flags(flags), _title(title), _description(description), _lockDate(lockDate) { } + _date(date), _flags(flags), _title(std::move(title)), _description(std::move(description)), _lockDate(lockDate) { } CalendarEvent() : _eventId(1), _ownerGUID(), _eventGuildId(UI64LIT(0)), _eventType(CALENDAR_TYPE_OTHER), _textureId(-1), _date(0), - _flags(0), _title(""), _description(""), _lockDate(0) { } + _flags(0), _title(), _description(), _lockDate(0) { } + + CalendarEvent(CalendarEvent const&) = delete; + CalendarEvent(CalendarEvent&&) = delete; + + CalendarEvent& operator=(CalendarEvent const&) = delete; + CalendarEvent& operator=(CalendarEvent&&) = delete; ~CalendarEvent(); @@ -263,7 +276,7 @@ struct TC_GAME_API CalendarEvent static bool IsGuildAnnouncement(uint32 flags) { return (flags & CALENDAR_FLAG_WITHOUT_INVITES) != 0; } std::string BuildCalendarMailSubject(ObjectGuid remover) const; - std::string BuildCalendarMailBody() const; + std::string BuildCalendarMailBody(Player const* invitee) const; private: uint64 _eventId; @@ -296,20 +309,26 @@ class TC_GAME_API CalendarMgr uint64 _maxInviteId; public: + CalendarMgr(CalendarMgr const&) = delete; + CalendarMgr(CalendarMgr&&) = delete; + + CalendarMgr& operator=(CalendarMgr const&) = delete; + CalendarMgr& operator=(CalendarMgr&&) = delete; + static CalendarMgr* instance(); void LoadFromDB(); CalendarEvent* GetEvent(uint64 eventId) const; CalendarEventStore const& GetEvents() const { return _events; } - CalendarEventStore GetEventsCreatedBy(ObjectGuid guid, bool includeGuildEvents = false); - CalendarEventStore GetPlayerEvents(ObjectGuid guid); - CalendarEventStore GetGuildEvents(ObjectGuid::LowType guildId); + CalendarEventStore GetEventsCreatedBy(ObjectGuid guid, bool includeGuildEvents = false) const; + CalendarEventStore GetPlayerEvents(ObjectGuid guid) const; + CalendarEventStore GetGuildEvents(ObjectGuid::LowType guildId) const; CalendarInvite* GetInvite(uint64 inviteId) const; CalendarEventInviteStore const& GetInvites() const { return _invites; } - CalendarInviteStore const& GetEventInvites(uint64 eventId); - CalendarInviteStore GetPlayerInvites(ObjectGuid guid); + CalendarInviteStore GetEventInvites(uint64 eventId) const; + CalendarInviteStore GetPlayerInvites(ObjectGuid guid) const; void FreeEventId(uint64 id); uint64 GetFreeEventId(); @@ -332,19 +351,20 @@ class TC_GAME_API CalendarMgr void RemoveAllPlayerEventsAndInvites(ObjectGuid guid); void RemovePlayerGuildEventsAndSignups(ObjectGuid guid, ObjectGuid::LowType guildId); - void SendCalendarEvent(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarSendEventType sendType); - void SendCalendarEventInvite(CalendarInvite const& invite); - void SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite); - void SendCalendarEventInviteRemove(CalendarEvent const& calendarEvent, CalendarInvite const& invite, uint32 flags); - void SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarInviteStatus status); - void SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t originalDate); - void SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite); - void SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent); - void SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite); - void SendCalendarClearPendingAction(ObjectGuid guid); - void SendCalendarCommandResult(ObjectGuid guid, CalendarError err, char const* param = nullptr); - - void SendPacketToAllEventRelatives(WorldPacket const* packet, CalendarEvent const& calendarEvent); + void SendCalendarEvent(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarSendEventType sendType) const; + void SendCalendarEventInvite(CalendarInvite const& invite) const; + void SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const; + void SendCalendarEventInviteRemove(CalendarEvent const& calendarEvent, CalendarInvite const& invite, uint32 flags) const; + void SendCalendarEventInviteRemoveAlert(ObjectGuid guid, CalendarEvent const& calendarEvent, CalendarInviteStatus status) const; + void SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t originalDate) const; + void SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const; + void SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent) const; + void SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const; + void SendCalendarClearPendingAction(ObjectGuid guid) const; + void SendCalendarCommandResult(ObjectGuid guid, CalendarError err, char const* param = nullptr) const; + + void SendPacketToAllEventRelatives(WorldPacket const* packet, CalendarEvent const& calendarEvent) const; + std::vector<Player*> GetAllEventRelatives(CalendarEvent const& calendarEvent) const; }; #define sCalendarMgr CalendarMgr::instance() diff --git a/src/server/game/Conditions/ConditionMgr.cpp b/src/server/game/Conditions/ConditionMgr.cpp index 0c59309bbb7..a7a74704a5d 100644 --- a/src/server/game/Conditions/ConditionMgr.cpp +++ b/src/server/game/Conditions/ConditionMgr.cpp @@ -19,12 +19,12 @@ #include "AchievementMgr.h" #include "AreaTrigger.h" #include "AreaTriggerDataStore.h" -#include "Battleground.h" #include "BattlePetMgr.h" +#include "Battleground.h" #include "Containers.h" #include "ConversationDataStore.h" -#include "DatabaseEnv.h" #include "DB2Stores.h" +#include "DatabaseEnv.h" #include "GameEventMgr.h" #include "GameObject.h" #include "GameTime.h" @@ -32,8 +32,8 @@ #include "InstanceScenario.h" #include "InstanceScript.h" #include "Item.h" -#include "LanguageMgr.h" #include "LFGMgr.h" +#include "LanguageMgr.h" #include "Log.h" #include "LootMgr.h" #include "Map.h" @@ -53,6 +53,7 @@ #include "World.h" #include "WorldSession.h" #include "WorldStateMgr.h" +#include "WowTime.h" #include <random> #include <sstream> @@ -3239,15 +3240,18 @@ bool ConditionMgr::IsPlayerMeetingCondition(Player const* player, PlayerConditio if (condition->Time[0]) { - ByteBuffer unpacker; - unpacker << condition->Time[0]; - time_t from = unpacker.ReadPackedTime(); - unpacker.rpos(0); - unpacker.wpos(0); - unpacker << condition->Time[1]; - time_t to = unpacker.ReadPackedTime(); + WowTime time0; + time0.SetPackedTime(condition->Time[0]); + + if (condition->Time[1]) + { + WowTime time1; + time1.SetPackedTime(condition->Time[1]); - if (GameTime::GetGameTime() < from || GameTime::GetGameTime() > to) + if (!GameTime::GetWowTime()->IsInRange(time0, time1)) + return false; + } + else if (*GameTime::GetWowTime() != time0) return false; } diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index a93c6444d3b..531a103cc30 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -23354,8 +23354,8 @@ void Player::SendInitialPacketsBeforeAddToMap() static float const TimeSpeed = 0.01666667f; WorldPackets::Misc::LoginSetTimeSpeed loginSetTimeSpeed; loginSetTimeSpeed.NewSpeed = TimeSpeed; - loginSetTimeSpeed.GameTime = GameTime::GetGameTime(); - loginSetTimeSpeed.ServerTime = GameTime::GetGameTime(); + loginSetTimeSpeed.GameTime = *GameTime::GetWowTime(); + loginSetTimeSpeed.ServerTime = *GameTime::GetWowTime(); loginSetTimeSpeed.GameTimeHolidayOffset = 0; /// @todo loginSetTimeSpeed.ServerTimeHolidayOffset = 0; /// @todo SendDirectMessage(loginSetTimeSpeed.Write()); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 035d8e00f3e..9874302350d 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -226,7 +226,7 @@ void Guild::NewsLogEntry::WritePacket(WorldPackets::Guild::GuildNews& newsPacket WorldPackets::Guild::GuildNewsEvent newsEvent; newsEvent.Id = int32(GetGUID()); newsEvent.MemberGuid = GetPlayerGuid(); - newsEvent.CompletedDate = uint32(GetTimestamp()); + newsEvent.CompletedDate.SetUtcTimeFromUnixTime(GetTimestamp()); newsEvent.Flags = int32(GetFlags()); newsEvent.Type = int32(GetType()); @@ -1306,7 +1306,8 @@ void Guild::HandleRoster(WorldSession* session) WorldPackets::Guild::GuildRoster roster; roster.NumAccounts = int32(m_accountsNumber); - roster.CreateDate = uint32(m_createdDate); + roster.CreateDate.SetUtcTimeFromUnixTime(m_createdDate); + roster.CreateDate += session->GetTimezoneOffset(); roster.GuildFlags = 0; roster.MemberData.reserve(m_members.size()); @@ -2183,7 +2184,10 @@ void Guild::SendNewsUpdate(WorldSession* session) const packet.NewsEvents.reserve(newsLog.size()); for (NewsLogEntry const& newsLogEntry : newsLog) + { newsLogEntry.WritePacket(packet); + packet.NewsEvents.back().CompletedDate += session->GetTimezoneOffset(); + } session->SendPacket(packet.Write()); @@ -2688,12 +2692,15 @@ void Guild::BroadcastPacket(WorldPacket const* packet) const player->SendDirectMessage(packet); } -void Guild::BroadcastPacketIfTrackingAchievement(WorldPacket const* packet, uint32 criteriaId) const +std::vector<Player*> Guild::GetMembersTrackingCriteria(uint32 criteriaId) const { + std::vector<Player*> members; for (auto const& [guid, member] : m_members) if (member.IsTrackingCriteriaId(criteriaId)) if (Player* player = member.FindPlayer()) - player->GetSession()->SendPacket(packet); + members.push_back(player); + + return members; } void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, GuildRankOrder minRank) @@ -3599,10 +3606,16 @@ void Guild::AddGuildNews(uint8 type, ObjectGuid guid, uint32 flags, uint32 value NewsLogEntry& news = m_newsLog.AddEvent(trans, m_id, m_newsLog.GetNextGUID(), GuildNews(type), guid, flags, value); CharacterDatabase.CommitTransaction(trans); - WorldPackets::Guild::GuildNews newsPacket; - newsPacket.NewsEvents.reserve(1); - news.WritePacket(newsPacket); - BroadcastPacket(newsPacket.Write()); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Guild::GuildNews newsPacket; + newsPacket.NewsEvents.reserve(1); + news.WritePacket(newsPacket); + newsPacket.NewsEvents.back().CompletedDate += receiver->GetSession()->GetTimezoneOffset(); + + receiver->SendDirectMessage(newsPacket.Write()); + }; + BroadcastWorker(packetBuilder); } bool Guild::HasAchieved(uint32 achievementId) const @@ -3637,5 +3650,6 @@ void Guild::HandleNewsSetSticky(WorldSession* session, uint32 newsId, bool stick WorldPackets::Guild::GuildNews newsPacket; newsPacket.NewsEvents.reserve(1); itr->WritePacket(newsPacket); + newsPacket.NewsEvents.back().CompletedDate += session->GetTimezoneOffset(); session->SendPacket(newsPacket.Write()); } diff --git a/src/server/game/Guilds/Guild.h b/src/server/game/Guilds/Guild.h index bdbd05503c4..071e2c881da 100644 --- a/src/server/game/Guilds/Guild.h +++ b/src/server/game/Guilds/Guild.h @@ -810,7 +810,6 @@ class TC_GAME_API Guild void BroadcastAddonToGuild(WorldSession* session, bool officerOnly, std::string_view msg, std::string_view prefix, bool isLogged) const; void BroadcastPacketToRank(WorldPacket const* packet, GuildRankId rankId) const; void BroadcastPacket(WorldPacket const* packet) const; - void BroadcastPacketIfTrackingAchievement(WorldPacket const* packet, uint32 criteriaId) const; void MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, GuildRankOrder minRank); @@ -831,6 +830,7 @@ class TC_GAME_API Guild bool IsMember(ObjectGuid guid) const; uint32 GetMembersCount() const { return uint32(m_members.size()); } uint64 GetMemberAvailableMoneyForRepairItems(ObjectGuid guid) const; + std::vector<Player*> GetMembersTrackingCriteria(uint32 criteriaId) const; // Bank void SwapItems(Player* player, uint8 tabId, uint8 slotId, uint8 destTabId, uint8 destSlotId, uint32 splitedAmount); diff --git a/src/server/game/Handlers/AuthHandler.cpp b/src/server/game/Handlers/AuthHandler.cpp index 7be557d368b..13db0718450 100644 --- a/src/server/game/Handlers/AuthHandler.cpp +++ b/src/server/game/Handlers/AuthHandler.cpp @@ -26,6 +26,7 @@ #include "RBAC.h" #include "Realm.h" #include "SystemPackets.h" +#include "Timezone.h" #include "World.h" void WorldSession::SendAuthResponse(uint32 code, bool queued, uint32 queuePos) @@ -89,12 +90,14 @@ void WorldSession::SendClientCacheVersion(uint32 version) void WorldSession::SendSetTimeZoneInformation() { - /// @todo: replace dummy values - WorldPackets::System::SetTimeZoneInformation packet; - packet.ServerTimeTZ = "Europe/Paris"; - packet.GameTimeTZ = "Europe/Paris"; - packet.ServerRegionalTZ = "Europe/Paris"; + Minutes timezoneOffset = Trinity::Timezone::GetSystemZoneOffset(false); + std::string realTimezone = Trinity::Timezone::GetSystemZoneName(); + std::string_view clientSupportedTZ = Trinity::Timezone::FindClosestClientSupportedTimezone(realTimezone, timezoneOffset); + WorldPackets::System::SetTimeZoneInformation packet; + packet.ServerTimeTZ = clientSupportedTZ; + packet.GameTimeTZ = clientSupportedTZ; + packet.ServerRegionalTZ = clientSupportedTZ; SendPacket(packet.Write()); } diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 209babfec10..ab512f54eec 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -39,7 +39,6 @@ Copied events should probably have a new owner #include "CalendarPackets.h" #include "CharacterCache.h" #include "DatabaseEnv.h" -#include "DB2Stores.h" #include "GameTime.h" #include "Guild.h" #include "GuildMgr.h" @@ -49,16 +48,14 @@ Copied events should probably have a new owner #include "ObjectMgr.h" #include "Player.h" #include "SocialMgr.h" -#include "Util.h" #include "World.h" void WorldSession::HandleCalendarGetCalendar(WorldPackets::Calendar::CalendarGetCalendar& /*calendarGetCalendar*/) { ObjectGuid guid = _player->GetGUID(); - time_t currTime = GameTime::GetGameTime(); WorldPackets::Calendar::CalendarSendCalendar packet; - packet.ServerTime = currTime; + packet.ServerTime = *GameTime::GetWowTime(); CalendarInviteStore playerInvites = sCalendarMgr->GetPlayerInvites(guid); for (CalendarInvite const* invite : playerInvites) @@ -78,7 +75,8 @@ void WorldSession::HandleCalendarGetCalendar(WorldPackets::Calendar::CalendarGet { WorldPackets::Calendar::CalendarSendCalendarEventInfo& eventInfo = packet.Events.emplace_back(); eventInfo.EventID = event->GetEventId(); - eventInfo.Date = event->GetDate(); + eventInfo.Date.SetUtcTimeFromUnixTime(event->GetDate()); + eventInfo.Date += GetTimezoneOffset(); eventInfo.EventClubID = event->GetGuildId(); eventInfo.EventName = event->GetTitle(); eventInfo.EventType = event->GetType(); @@ -117,11 +115,10 @@ void WorldSession::HandleCalendarAddEvent(WorldPackets::Calendar::CalendarAddEve { ObjectGuid guid = _player->GetGUID(); - calendarAddEvent.EventInfo.Time = uint32(LocalTimeToUTCTime(calendarAddEvent.EventInfo.Time)); + calendarAddEvent.EventInfo.Time -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarAddEvent.EventInfo.Time < (GameTime::GetGameTime() - time_t(86400L))) + if (calendarAddEvent.EventInfo.Time < *GameTime::GetUtcWowTime()) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_PASSED); return; @@ -163,7 +160,7 @@ void WorldSession::HandleCalendarAddEvent(WorldPackets::Calendar::CalendarAddEve SetCalendarEventCreationCooldown(GameTime::GetGameTime() + CALENDAR_CREATE_EVENT_COOLDOWN); CalendarEvent* calendarEvent = new CalendarEvent(sCalendarMgr->GetFreeEventId(), guid, UI64LIT(0), CalendarEventType(calendarAddEvent.EventInfo.EventType), calendarAddEvent.EventInfo.TextureID, - calendarAddEvent.EventInfo.Time, calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, time_t(0)); + calendarAddEvent.EventInfo.Time.GetUnixTimeFromUtcTime(), calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, time_t(0)); if (calendarEvent->IsGuildEvent() || calendarEvent->IsGuildAnnouncement()) calendarEvent->SetGuildId(_player->GetGuildId()); @@ -201,11 +198,10 @@ void WorldSession::HandleCalendarUpdateEvent(WorldPackets::Calendar::CalendarUpd ObjectGuid guid = _player->GetGUID(); time_t oldEventTime = time_t(0); - calendarUpdateEvent.EventInfo.Time = uint32(LocalTimeToUTCTime(calendarUpdateEvent.EventInfo.Time)); + calendarUpdateEvent.EventInfo.Time -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarUpdateEvent.EventInfo.Time < (GameTime::GetGameTime() - time_t(86400L))) + if (calendarUpdateEvent.EventInfo.Time < *GameTime::GetUtcWowTime()) return; if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarUpdateEvent.EventInfo.EventID)) @@ -214,7 +210,7 @@ void WorldSession::HandleCalendarUpdateEvent(WorldPackets::Calendar::CalendarUpd calendarEvent->SetType(CalendarEventType(calendarUpdateEvent.EventInfo.EventType)); calendarEvent->SetFlags(calendarUpdateEvent.EventInfo.Flags); - calendarEvent->SetDate(calendarUpdateEvent.EventInfo.Time); + calendarEvent->SetDate(calendarUpdateEvent.EventInfo.Time.GetUnixTimeFromUtcTime()); calendarEvent->SetTextureId(calendarUpdateEvent.EventInfo.TextureID); calendarEvent->SetTitle(calendarUpdateEvent.EventInfo.Title); calendarEvent->SetDescription(calendarUpdateEvent.EventInfo.Description); @@ -236,11 +232,10 @@ void WorldSession::HandleCalendarCopyEvent(WorldPackets::Calendar::CalendarCopyE { ObjectGuid guid = _player->GetGUID(); - calendarCopyEvent.Date = uint32(LocalTimeToUTCTime(calendarCopyEvent.Date)); + calendarCopyEvent.Date -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarCopyEvent.Date < (GameTime::GetGameTime() - time_t(86400L))) + if (calendarCopyEvent.Date < *GameTime::GetUtcWowTime()) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_PASSED); return; @@ -292,7 +287,7 @@ void WorldSession::HandleCalendarCopyEvent(WorldPackets::Calendar::CalendarCopyE SetCalendarEventCreationCooldown(GameTime::GetGameTime() + CALENDAR_CREATE_EVENT_COOLDOWN); CalendarEvent* newEvent = new CalendarEvent(*oldEvent, sCalendarMgr->GetFreeEventId()); - newEvent->SetDate(calendarCopyEvent.Date); + newEvent->SetDate(calendarCopyEvent.Date.GetUnixTimeFromUtcTime()); sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); CalendarInviteStore invites = sCalendarMgr->GetEventInvites(calendarCopyEvent.EventID); @@ -550,7 +545,7 @@ void WorldSession::HandleSetSavedInstanceExtend(WorldPackets::Calendar::SetSaved return; WorldPackets::Calendar::CalendarRaidLockoutUpdated calendarRaidLockoutUpdated; - calendarRaidLockoutUpdated.ServerTime = GameTime::GetGameTime(); + calendarRaidLockoutUpdated.ServerTime = *GameTime::GetWowTime(); calendarRaidLockoutUpdated.MapID = setSavedInstanceExtend.MapID; calendarRaidLockoutUpdated.DifficultyID = setSavedInstanceExtend.DifficultyID; calendarRaidLockoutUpdated.OldTimeRemaining = std::max(std::chrono::duration_cast<Seconds>(expiryTimes.first - GameTime::GetSystemTime()).count(), SI64LIT(0)); diff --git a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp index a72c213a042..798e90e6b26 100644 --- a/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp +++ b/src/server/game/Quests/QuestObjectiveCriteriaMgr.cpp @@ -25,6 +25,7 @@ #include "Map.h" #include "ObjectMgr.h" #include "Player.h" +#include "WorldSession.h" QuestObjectiveCriteriaMgr::QuestObjectiveCriteriaMgr(Player* owner) : _owner(owner) { @@ -187,7 +188,8 @@ void QuestObjectiveCriteriaMgr::SendAllData(Player const* /*receiver*/) const criteriaUpdate.PlayerGUID = _owner->GetGUID(); criteriaUpdate.Flags = 0; - criteriaUpdate.CurrentTime = criteriaProgres.second.Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(criteriaProgres.second.Date); + criteriaUpdate.CurrentTime += _owner->GetSession()->GetTimezoneOffset(); criteriaUpdate.CreationTime = 0; SendPacket(criteriaUpdate.Write()); @@ -222,7 +224,8 @@ void QuestObjectiveCriteriaMgr::SendCriteriaUpdate(Criteria const* criteria, Cri if (criteria->Entry->StartTimer) criteriaUpdate.Flags = timedCompleted ? 1 : 0; // 1 is for keeping the counter at 0 in client - criteriaUpdate.CurrentTime = progress->Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(progress->Date); + criteriaUpdate.CurrentTime += _owner->GetSession()->GetTimezoneOffset(); criteriaUpdate.ElapsedTime = timeElapsed; criteriaUpdate.CreationTime = 0; diff --git a/src/server/game/Scenarios/Scenario.cpp b/src/server/game/Scenarios/Scenario.cpp index 3366781ba39..ce994618d62 100644 --- a/src/server/game/Scenarios/Scenario.cpp +++ b/src/server/game/Scenarios/Scenario.cpp @@ -23,6 +23,7 @@ #include "Player.h" #include "ScenarioMgr.h" #include "ScenarioPackets.h" +#include "WorldSession.h" Scenario::Scenario(Map* map, ScenarioData const* scenarioData) : _map(map), _data(scenarioData), _guid(ObjectGuid::Create<HighGuid::Scenario>(map->GetId(), scenarioData->Entry->ID, map->GenerateLowGuid<HighGuid::Scenario>())), @@ -100,9 +101,12 @@ void Scenario::SetStep(ScenarioStepEntry const* step) player->StartCriteria(CriteriaStartEvent::BeginScenarioStep, step->ID); } - WorldPackets::Scenario::ScenarioState scenarioState; - BuildScenarioState(&scenarioState); - SendPacket(scenarioState.Write()); + DoForAllPlayers([&](Player const* receiver) + { + WorldPackets::Scenario::ScenarioState scenarioState; + BuildScenarioStateFor(receiver, &scenarioState); + receiver->SendDirectMessage(scenarioState.Write()); + }); } void Scenario::OnPlayerEnter(Player* player) @@ -117,7 +121,7 @@ void Scenario::OnPlayerExit(Player* player) SendBootPlayer(player); } -bool Scenario::IsComplete() +bool Scenario::IsComplete() const { for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) { @@ -136,7 +140,7 @@ ScenarioEntry const* Scenario::GetEntry() const return _data->Entry; } -ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) +ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) const { auto itr = _stepStates.find(step); if (itr == _stepStates.end()) @@ -145,20 +149,24 @@ ScenarioStepState Scenario::GetStepState(ScenarioStepEntry const* step) return itr->second; } -void Scenario::SendCriteriaUpdate(Criteria const * criteria, CriteriaProgress const * progress, Seconds timeElapsed, bool timedCompleted) const +void Scenario::SendCriteriaUpdate(Criteria const* criteria, CriteriaProgress const* progress, Seconds timeElapsed, bool timedCompleted) const { - WorldPackets::Scenario::ScenarioProgressUpdate progressUpdate; - progressUpdate.CriteriaProgress.Id = criteria->ID; - progressUpdate.CriteriaProgress.Quantity = progress->Counter; - progressUpdate.CriteriaProgress.Player = progress->PlayerGUID; - progressUpdate.CriteriaProgress.Date = progress->Date; - if (criteria->Entry->StartTimer) - progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0; - - progressUpdate.CriteriaProgress.TimeFromStart = timeElapsed; - progressUpdate.CriteriaProgress.TimeFromCreate = Seconds::zero(); - - SendPacket(progressUpdate.Write()); + DoForAllPlayers([=](Player const* receiver) + { + WorldPackets::Scenario::ScenarioProgressUpdate progressUpdate; + progressUpdate.CriteriaProgress.Id = criteria->ID; + progressUpdate.CriteriaProgress.Quantity = progress->Counter; + progressUpdate.CriteriaProgress.Player = progress->PlayerGUID; + progressUpdate.CriteriaProgress.Date.SetUtcTimeFromUnixTime(progress->Date); + progressUpdate.CriteriaProgress.Date += receiver->GetSession()->GetTimezoneOffset(); + if (criteria->Entry->StartTimer) + progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0; + + progressUpdate.CriteriaProgress.TimeFromStart = timeElapsed; + progressUpdate.CriteriaProgress.TimeFromCreate = Seconds::zero(); + + receiver->SendDirectMessage(progressUpdate.Write()); + }); } bool Scenario::CanUpdateCriteriaTree(Criteria const * /*criteria*/, CriteriaTree const * tree, Player * /*referencePlayer*/) const @@ -220,20 +228,28 @@ bool Scenario::IsCompletedStep(ScenarioStepEntry const* step) return IsCompletedCriteriaTree(tree); } -void Scenario::SendPacket(WorldPacket const* data) const +void Scenario::DoForAllPlayers(std::function<void(Player*)> const& worker) const { for (ObjectGuid guid : _players) if (Player* player = ObjectAccessor::GetPlayer(_map, guid)) - player->SendDirectMessage(data); + worker(player); } -void Scenario::BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenarioState) +void Scenario::SendPacket(WorldPacket const* data) const +{ + DoForAllPlayers([data](Player const* player) + { + player->SendDirectMessage(data); + }); +} + +void Scenario::BuildScenarioStateFor(Player const* player, WorldPackets::Scenario::ScenarioState* scenarioState) const { scenarioState->ScenarioGUID = _guid; scenarioState->ScenarioID = _data->Entry->ID; if (ScenarioStepEntry const* step = GetStep()) scenarioState->CurrentStep = step->ID; - scenarioState->CriteriaProgress = GetCriteriasProgress(); + scenarioState->CriteriaProgress = GetCriteriasProgressFor(player); scenarioState->BonusObjectives = GetBonusObjectivesData(); // Don't know exactly what this is for, but seems to contain list of scenario steps that we're either on or that are completed for (std::pair<ScenarioStepEntry const* const, ScenarioStepState> const& state : _stepStates) @@ -288,14 +304,14 @@ ScenarioStepEntry const* Scenario::GetLastStep() const return lastStep; } -void Scenario::SendScenarioState(Player* player) +void Scenario::SendScenarioState(Player const* player) const { WorldPackets::Scenario::ScenarioState scenarioState; - BuildScenarioState(&scenarioState); + BuildScenarioStateFor(player, &scenarioState); player->SendDirectMessage(scenarioState.Write()); } -std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() +std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObjectivesData() const { std::vector<WorldPackets::Scenario::BonusObjectiveData> bonusObjectivesData; for (std::pair<uint8 const, ScenarioStepEntry const*> const& scenarioStep : _data->Steps) @@ -315,21 +331,18 @@ std::vector<WorldPackets::Scenario::BonusObjectiveData> Scenario::GetBonusObject return bonusObjectivesData; } -std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasProgress() +std::vector<WorldPackets::Achievement::CriteriaProgress> Scenario::GetCriteriasProgressFor(Player const* player) const { std::vector<WorldPackets::Achievement::CriteriaProgress> criteriasProgress; - if (!_criteriaProgress.empty()) + for (auto const& [criteriaId, progress] : _criteriaProgress) { - for (std::pair<uint32 const, CriteriaProgress> const& progressPair : _criteriaProgress) - { - WorldPackets::Achievement::CriteriaProgress criteriaProgress; - criteriaProgress.Id = progressPair.first; - criteriaProgress.Quantity = progressPair.second.Counter; - criteriaProgress.Date = progressPair.second.Date; - criteriaProgress.Player = progressPair.second.PlayerGUID; - criteriasProgress.push_back(criteriaProgress); - } + WorldPackets::Achievement::CriteriaProgress& criteriaProgress = criteriasProgress.emplace_back(); + criteriaProgress.Id = criteriaId; + criteriaProgress.Quantity = progress.Counter; + criteriaProgress.Date.SetUtcTimeFromUnixTime(progress.Date); + criteriaProgress.Date += player->GetSession()->GetTimezoneOffset(); + criteriaProgress.Player = progress.PlayerGUID; } return criteriasProgress; @@ -340,7 +353,7 @@ CriteriaList const& Scenario::GetCriteriaByType(CriteriaType type, uint32 /*asse return sCriteriaMgr->GetScenarioCriteriaByTypeAndScenario(type, _data->Entry->ID); } -void Scenario::SendBootPlayer(Player* player) +void Scenario::SendBootPlayer(Player const* player) const { WorldPackets::Scenario::ScenarioVacate scenarioBoot; scenarioBoot.ScenarioGUID = _guid; diff --git a/src/server/game/Scenarios/Scenario.h b/src/server/game/Scenarios/Scenario.h index 7c632eca0cb..d70331adbdc 100644 --- a/src/server/game/Scenarios/Scenario.h +++ b/src/server/game/Scenarios/Scenario.h @@ -65,17 +65,17 @@ class TC_GAME_API Scenario : public CriteriaHandler virtual void OnPlayerExit(Player* player); virtual void Update(uint32 /*diff*/) { } - bool IsComplete(); + bool IsComplete() const; bool IsCompletedStep(ScenarioStepEntry const* step); void SetStepState(ScenarioStepEntry const* step, ScenarioStepState state) { _stepStates[step] = state; } ScenarioEntry const* GetEntry() const; - ScenarioStepState GetStepState(ScenarioStepEntry const* step); + ScenarioStepState GetStepState(ScenarioStepEntry const* step) const; ScenarioStepEntry const* GetStep() const { return _currentstep; } ScenarioStepEntry const* GetFirstStep() const; ScenarioStepEntry const* GetLastStep() const; - void SendScenarioState(Player* player); - void SendBootPlayer(Player* player); + void SendScenarioState(Player const* player) const; + void SendBootPlayer(Player const* player) const; protected: Map const* _map; @@ -89,14 +89,15 @@ class TC_GAME_API Scenario : public CriteriaHandler void CompletedCriteriaTree(CriteriaTree const* tree, Player* referencePlayer) override; void AfterCriteriaTreeUpdate(CriteriaTree const* /*tree*/, Player* /*referencePlayer*/) override { } + void DoForAllPlayers(std::function<void(Player*)> const& worker) const; void SendPacket(WorldPacket const* data) const override; void SendAllData(Player const* /*receiver*/) const override { } - void BuildScenarioState(WorldPackets::Scenario::ScenarioState* scenarioState); + void BuildScenarioStateFor(Player const* player, WorldPackets::Scenario::ScenarioState* scenarioState) const; - std::vector<WorldPackets::Scenario::BonusObjectiveData> GetBonusObjectivesData(); - std::vector<WorldPackets::Achievement::CriteriaProgress> GetCriteriasProgress(); + std::vector<WorldPackets::Scenario::BonusObjectiveData> GetBonusObjectivesData() const; + std::vector<WorldPackets::Achievement::CriteriaProgress> GetCriteriasProgressFor(Player const* player) const; CriteriaList const& GetCriteriaByType(CriteriaType type, uint32 asset) const override; ScenarioData const* _data; diff --git a/src/server/game/Server/Packets/AchievementPackets.cpp b/src/server/game/Server/Packets/AchievementPackets.cpp index d158db68e60..cf8111ba8b4 100644 --- a/src/server/game/Server/Packets/AchievementPackets.cpp +++ b/src/server/game/Server/Packets/AchievementPackets.cpp @@ -17,24 +17,26 @@ #include "AchievementPackets.h" -ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::EarnedAchievement const& earned) +namespace WorldPackets::Achievement +{ +ByteBuffer& operator<<(ByteBuffer& data, EarnedAchievement const& earned) { data << uint32(earned.Id); - data.AppendPackedTime(earned.Date); + data << earned.Date; data << earned.Owner; data << uint32(earned.VirtualRealmAddress); data << uint32(earned.NativeRealmAddress); return data; } -ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::CriteriaProgress const& criteria) +ByteBuffer& operator<<(ByteBuffer& data, CriteriaProgress const& criteria) { data << uint32(criteria.Id); data << uint64(criteria.Quantity); data << criteria.Player; data << uint32(criteria.Unused_10_1_5); data << uint32(criteria.Flags); - data.AppendPackedTime(criteria.Date); + data << criteria.Date; data << criteria.TimeFromStart; data << criteria.TimeFromCreate; data.WriteBit(criteria.RafAcceptanceID.has_value()); @@ -46,37 +48,37 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::CriteriaProg return data; } -ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::AllAchievements const& allAchievements) +ByteBuffer& operator<<(ByteBuffer& data, AllAchievements const& allAchievements) { data << uint32(allAchievements.Earned.size()); data << uint32(allAchievements.Progress.size()); - for (WorldPackets::Achievement::EarnedAchievement const& earned : allAchievements.Earned) + for (EarnedAchievement const& earned : allAchievements.Earned) data << earned; - for (WorldPackets::Achievement::CriteriaProgress const& progress : allAchievements.Progress) + for (CriteriaProgress const& progress : allAchievements.Progress) data << progress; return data; } -WorldPacket const* WorldPackets::Achievement::AllAchievementData::Write() +WorldPacket const* AllAchievementData::Write() { _worldPacket << Data; return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::AllAccountCriteria::Write() +WorldPacket const* AllAccountCriteria::Write() { _worldPacket << uint32(Progress.size()); - for (WorldPackets::Achievement::CriteriaProgress const& progress : Progress) + for (CriteriaProgress const& progress : Progress) _worldPacket << progress; return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::RespondInspectAchievements::Write() +WorldPacket const* RespondInspectAchievements::Write() { _worldPacket << Player; _worldPacket << Data; @@ -84,14 +86,14 @@ WorldPacket const* WorldPackets::Achievement::RespondInspectAchievements::Write( return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::CriteriaUpdate::Write() +WorldPacket const* CriteriaUpdate::Write() { _worldPacket << uint32(CriteriaID); _worldPacket << uint64(Quantity); _worldPacket << PlayerGUID; _worldPacket << uint32(Unused_10_1_5); _worldPacket << uint32(Flags); - _worldPacket.AppendPackedTime(CurrentTime); + _worldPacket << CurrentTime; _worldPacket << ElapsedTime; _worldPacket << CreationTime; _worldPacket.WriteBit(RafAcceptanceID.has_value()); @@ -103,21 +105,21 @@ WorldPacket const* WorldPackets::Achievement::CriteriaUpdate::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::AccountCriteriaUpdate::Write() +WorldPacket const* AccountCriteriaUpdate::Write() { _worldPacket << Progress; return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::CriteriaDeleted::Write() +WorldPacket const* CriteriaDeleted::Write() { _worldPacket << uint32(CriteriaID); return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::AchievementDeleted::Write() +WorldPacket const* AchievementDeleted::Write() { _worldPacket << uint32(AchievementID); _worldPacket << uint32(Immunities); @@ -125,12 +127,12 @@ WorldPacket const* WorldPackets::Achievement::AchievementDeleted::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::AchievementEarned::Write() +WorldPacket const* AchievementEarned::Write() { _worldPacket << Sender; _worldPacket << Earner; _worldPacket << uint32(AchievementID); - _worldPacket.AppendPackedTime(Time); + _worldPacket << Time; _worldPacket << uint32(EarnerNativeRealm); _worldPacket << uint32(EarnerVirtualRealm); _worldPacket.WriteBit(Initial); @@ -139,7 +141,7 @@ WorldPacket const* WorldPackets::Achievement::AchievementEarned::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::BroadcastAchievement::Write() +WorldPacket const* BroadcastAchievement::Write() { _worldPacket.WriteBits(Name.length(), 7); _worldPacket.WriteBit(GuildAchievement); @@ -150,7 +152,7 @@ WorldPacket const* WorldPackets::Achievement::BroadcastAchievement::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::GuildCriteriaUpdate::Write() +WorldPacket const* GuildCriteriaUpdate::Write() { _worldPacket << uint32(Progress.size()); @@ -159,8 +161,7 @@ WorldPacket const* WorldPackets::Achievement::GuildCriteriaUpdate::Write() _worldPacket << int32(progress.CriteriaID); _worldPacket << progress.DateCreated; _worldPacket << progress.DateStarted; - _worldPacket.AppendPackedTime(progress.DateUpdated); - _worldPacket << uint32(0); // this is a hack. this is a packed time written as int64 (progress.DateUpdated) + _worldPacket << int64(progress.DateUpdated.GetPackedTime()); _worldPacket << uint64(progress.Quantity); _worldPacket << progress.PlayerGUID; _worldPacket << int32(progress.Unused_10_1_5); @@ -170,7 +171,7 @@ WorldPacket const* WorldPackets::Achievement::GuildCriteriaUpdate::Write() return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::GuildCriteriaDeleted::Write() +WorldPacket const* GuildCriteriaDeleted::Write() { _worldPacket << GuildGUID; _worldPacket << int32(CriteriaID); @@ -178,30 +179,30 @@ WorldPacket const* WorldPackets::Achievement::GuildCriteriaDeleted::Write() return &_worldPacket; } -void WorldPackets::Achievement::GuildSetFocusedAchievement::Read() +void GuildSetFocusedAchievement::Read() { _worldPacket >> AchievementID; } -WorldPacket const* WorldPackets::Achievement::GuildAchievementDeleted::Write() +WorldPacket const* GuildAchievementDeleted::Write() { _worldPacket << GuildGUID; _worldPacket << uint32(AchievementID); - _worldPacket.AppendPackedTime(TimeDeleted); + _worldPacket << TimeDeleted; return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::GuildAchievementEarned::Write() +WorldPacket const* GuildAchievementEarned::Write() { _worldPacket << GuildGUID; _worldPacket << uint32(AchievementID); - _worldPacket.AppendPackedTime(TimeEarned); + _worldPacket << TimeEarned; return &_worldPacket; } -WorldPacket const* WorldPackets::Achievement::AllGuildAchievements::Write() +WorldPacket const* AllGuildAchievements::Write() { _worldPacket << uint32(Earned.size()); @@ -211,20 +212,20 @@ WorldPacket const* WorldPackets::Achievement::AllGuildAchievements::Write() return &_worldPacket; } -void WorldPackets::Achievement::GuildGetAchievementMembers::Read() +void GuildGetAchievementMembers::Read() { _worldPacket >> PlayerGUID; _worldPacket >> GuildGUID; _worldPacket >> AchievementID; } -ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::GuildAchievementMember const& guildAchievementMember) +ByteBuffer& operator<<(ByteBuffer& data, GuildAchievementMember const& guildAchievementMember) { data << guildAchievementMember.MemberGUID; return data; } -WorldPacket const* WorldPackets::Achievement::GuildAchievementMembers::Write() +WorldPacket const* GuildAchievementMembers::Write() { _worldPacket << GuildGUID; _worldPacket << int32(AchievementID); @@ -234,3 +235,4 @@ WorldPacket const* WorldPackets::Achievement::GuildAchievementMembers::Write() return &_worldPacket; } +} diff --git a/src/server/game/Server/Packets/AchievementPackets.h b/src/server/game/Server/Packets/AchievementPackets.h index 39aa72aba16..8e2bbf14dfb 100644 --- a/src/server/game/Server/Packets/AchievementPackets.h +++ b/src/server/game/Server/Packets/AchievementPackets.h @@ -22,6 +22,7 @@ #include "ObjectGuid.h" #include "Optional.h" #include "PacketUtilities.h" +#include "WowTime.h" namespace WorldPackets { @@ -30,7 +31,7 @@ namespace WorldPackets struct EarnedAchievement { uint32 Id = 0; - time_t Date = time_t(0); + WowTime Date; ObjectGuid Owner; uint32 VirtualRealmAddress = 0; uint32 NativeRealmAddress = 0; @@ -43,7 +44,7 @@ namespace WorldPackets ObjectGuid Player; uint32 Unused_10_1_5 = 0; uint32 Flags = 0; - time_t Date = time_t(0); + WowTime Date; Duration<Seconds> TimeFromStart; Duration<Seconds> TimeFromCreate; Optional<uint64> RafAcceptanceID; @@ -98,7 +99,7 @@ namespace WorldPackets ObjectGuid PlayerGUID; uint32 Unused_10_1_5 = 0; uint32 Flags = 0; - time_t CurrentTime = time_t(0); + WowTime CurrentTime; Duration<Seconds> ElapsedTime; Timestamp<> CreationTime; Optional<uint64> RafAcceptanceID; @@ -146,7 +147,7 @@ namespace WorldPackets uint32 EarnerNativeRealm = 0; uint32 EarnerVirtualRealm = 0; uint32 AchievementID = 0; - time_t Time = time_t(0); + WowTime Time; bool Initial = false; ObjectGuid Sender; }; @@ -169,7 +170,7 @@ namespace WorldPackets int32 CriteriaID = 0; Timestamp<> DateCreated; Timestamp<> DateStarted; - time_t DateUpdated = 0; + WowTime DateUpdated; uint64 Quantity = 0; ObjectGuid PlayerGUID; int32 Unused_10_1_5 = 0; @@ -216,7 +217,7 @@ namespace WorldPackets ObjectGuid GuildGUID; uint32 AchievementID = 0; - time_t TimeDeleted = time_t(0); + WowTime TimeDeleted; }; class GuildAchievementEarned final : public ServerPacket @@ -228,7 +229,7 @@ namespace WorldPackets uint32 AchievementID = 0; ObjectGuid GuildGUID; - time_t TimeEarned = time_t(0); + WowTime TimeEarned; }; class AllGuildAchievements final : public ServerPacket @@ -272,9 +273,9 @@ namespace WorldPackets int32 AchievementID = 0; std::vector<GuildAchievementMember> Member; }; + + ByteBuffer& operator<<(ByteBuffer& data, CriteriaProgress const& criteria); } } -ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Achievement::CriteriaProgress const& criteria); - #endif // game_AchievementPackets_h__ diff --git a/src/server/game/Server/Packets/CalendarPackets.cpp b/src/server/game/Server/Packets/CalendarPackets.cpp index 27a67d416a3..cd0e1d3d7be 100644 --- a/src/server/game/Server/Packets/CalendarPackets.cpp +++ b/src/server/game/Server/Packets/CalendarPackets.cpp @@ -21,7 +21,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCal { data << uint64(eventInfo.EventID); data << uint8(eventInfo.EventType); - data.AppendPackedTime(eventInfo.Date); + data << eventInfo.Date; data << uint32(eventInfo.Flags); data << int32(eventInfo.TextureID); data << uint64(eventInfo.EventClubID); @@ -67,8 +67,7 @@ ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarEventIn data << uint8(inviteInfo.Status); data << uint8(inviteInfo.Moderator); data << uint8(inviteInfo.InviteType); - - data.AppendPackedTime(inviteInfo.ResponseTime); + data << inviteInfo.ResponseTime; data.WriteBits(inviteInfo.Notes.size(), 8); data.FlushBits(); @@ -121,7 +120,7 @@ ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Calendar::CalendarAddEv buffer >> addEventInfo.ClubID; buffer >> addEventInfo.EventType; buffer >> addEventInfo.TextureID; - addEventInfo.Time = buffer.ReadPackedTime(); + buffer >> addEventInfo.Time; buffer >> addEventInfo.Flags; addEventInfo.Invites.resize(buffer.read<uint32>()); @@ -150,7 +149,7 @@ ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Calendar::CalendarUpdat buffer >> updateEventInfo.ModeratorID; buffer >> updateEventInfo.EventType; buffer >> updateEventInfo.TextureID; - updateEventInfo.Time = buffer.ReadPackedTime(); + buffer >> updateEventInfo.Time; buffer >> updateEventInfo.Flags; uint8 titleLen = buffer.ReadBits(8); @@ -181,7 +180,7 @@ void WorldPackets::Calendar::CalendarCopyEvent::Read() _worldPacket >> EventID; _worldPacket >> ModeratorID; _worldPacket >> EventClubID; - Date = _worldPacket.ReadPackedTime(); + _worldPacket >> Date; } void WorldPackets::Calendar::CalendarRSVP::Read() @@ -252,7 +251,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarInviteAdded::Write() _worldPacket << uint8(Level); _worldPacket << uint8(Status); _worldPacket << uint8(Type); - _worldPacket.AppendPackedTime(ResponseTime); + _worldPacket << ResponseTime; _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); @@ -262,7 +261,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarInviteAdded::Write() WorldPacket const* WorldPackets::Calendar::CalendarSendCalendar::Write() { - _worldPacket.AppendPackedTime(ServerTime); + _worldPacket << ServerTime; _worldPacket << uint32(Invites.size()); _worldPacket << uint32(Events.size()); _worldPacket << uint32(RaidLockouts.size()); @@ -287,8 +286,8 @@ WorldPacket const* WorldPackets::Calendar::CalendarSendEvent::Write() _worldPacket << uint8(GetEventType); _worldPacket << int32(TextureID); _worldPacket << uint32(Flags); - _worldPacket.AppendPackedTime(Date); - _worldPacket << uint32(LockDate); + _worldPacket << Date; + _worldPacket << LockDate; _worldPacket << uint64(EventClubID); _worldPacket << uint32(Invites.size()); _worldPacket.WriteBits(EventName.size(), 8); @@ -307,7 +306,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarSendEvent::Write() WorldPacket const* WorldPackets::Calendar::CalendarInviteAlert::Write() { _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(Date); + _worldPacket << Date; _worldPacket << uint32(Flags); _worldPacket << uint8(EventType); _worldPacket << int32(TextureID); @@ -331,10 +330,10 @@ WorldPacket const* WorldPackets::Calendar::CalendarInviteStatus::Write() { _worldPacket << InviteGuid; _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(Date); + _worldPacket << Date; _worldPacket << uint32(Flags); _worldPacket << uint8(Status); - _worldPacket.AppendPackedTime(ResponseTime); + _worldPacket << ResponseTime; _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); @@ -369,7 +368,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarModeratorStatus::Write() WorldPacket const* WorldPackets::Calendar::CalendarInviteRemovedAlert::Write() { _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(Date); + _worldPacket << Date; _worldPacket << uint32(Flags); _worldPacket << uint8(Status); @@ -381,9 +380,9 @@ WorldPacket const* WorldPackets::Calendar::CalendarEventUpdatedAlert::Write() _worldPacket << uint64(EventClubID); _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(OriginalDate); - _worldPacket.AppendPackedTime(Date); - _worldPacket << uint32(LockDate); + _worldPacket << OriginalDate; + _worldPacket << Date; + _worldPacket << LockDate; _worldPacket << uint32(Flags); _worldPacket << uint32(TextureID); _worldPacket << uint8(EventType); @@ -402,7 +401,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarEventUpdatedAlert::Write() WorldPacket const* WorldPackets::Calendar::CalendarEventRemovedAlert::Write() { _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(Date); + _worldPacket << Date; _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); @@ -450,7 +449,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutRemoved::Write() WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutUpdated::Write() { - _worldPacket.AppendPackedTime(ServerTime); + _worldPacket << ServerTime; _worldPacket << int32(MapID); _worldPacket << uint32(DifficultyID); _worldPacket << int32(OldTimeRemaining); @@ -474,7 +473,7 @@ WorldPacket const* WorldPackets::Calendar::CalendarCommunityInvite::Write() WorldPacket const* WorldPackets::Calendar::CalendarInviteStatusAlert::Write() { _worldPacket << uint64(EventID); - _worldPacket.AppendPackedTime(Date); + _worldPacket << Date; _worldPacket << uint32(Flags); _worldPacket << uint8(Status); diff --git a/src/server/game/Server/Packets/CalendarPackets.h b/src/server/game/Server/Packets/CalendarPackets.h index 7ef1a4976f8..4ac9b9b8a3b 100644 --- a/src/server/game/Server/Packets/CalendarPackets.h +++ b/src/server/game/Server/Packets/CalendarPackets.h @@ -23,6 +23,7 @@ #include "ObjectGuid.h" #include "Optional.h" #include "PacketUtilities.h" +#include "WowTime.h" namespace WorldPackets { @@ -76,7 +77,7 @@ namespace WorldPackets std::string Description; uint8 EventType = 0; int32 TextureID = 0; - time_t Time = time_t(0); + WowTime Time; uint32 Flags = 0; Array<CalendarAddEventInviteInfo, CALENDAR_MAX_INVITES> Invites; }; @@ -101,7 +102,7 @@ namespace WorldPackets std::string Description; uint8 EventType = 0; uint32 TextureID = 0; - time_t Time = time_t(0); + WowTime Time; uint32 Flags = 0; }; @@ -139,7 +140,7 @@ namespace WorldPackets uint64 ModeratorID = 0; uint64 EventID = 0; uint64 EventClubID = 0; - time_t Date = time_t(0); + WowTime Date; }; class CalendarInviteAdded final : public ServerPacket @@ -150,7 +151,7 @@ namespace WorldPackets WorldPacket const* Write() override; uint64 InviteID = 0; - time_t ResponseTime = time_t(0); + WowTime ResponseTime; uint8 Level = 100; ObjectGuid InviteGuid; uint64 EventID = 0; @@ -183,7 +184,7 @@ namespace WorldPackets uint64 EventID = 0; std::string EventName; uint8 EventType = 0; - time_t Date = time_t(0); + WowTime Date; uint32 Flags = 0; int32 TextureID = 0; uint64 EventClubID = 0; @@ -197,7 +198,7 @@ namespace WorldPackets WorldPacket const* Write() override; - time_t ServerTime = time_t(0); + WowTime ServerTime; std::vector<CalendarSendCalendarInviteInfo> Invites; std::vector<CalendarSendCalendarRaidLockoutInfo> RaidLockouts; std::vector<CalendarSendCalendarEventInfo> Events; @@ -207,7 +208,7 @@ namespace WorldPackets { ObjectGuid Guid; uint64 InviteID = 0; - time_t ResponseTime = time_t(0); + WowTime ResponseTime; uint8 Level = 1; uint8 Status = 0; uint8 Moderator = 0; @@ -225,8 +226,8 @@ namespace WorldPackets ObjectGuid OwnerGuid; uint64 EventClubID = 0; uint64 EventID = 0; - time_t Date = time_t(0); - time_t LockDate = time_t(0); + WowTime Date; + WowTime LockDate; uint32 Flags = 0; int32 TextureID = 0; uint8 GetEventType = 0; @@ -249,7 +250,7 @@ namespace WorldPackets uint64 InviteID = 0; uint64 EventID = 0; uint32 Flags = 0; - time_t Date = time_t(0); + WowTime Date; int32 TextureID = 0; uint8 Status = 0; uint8 EventType = 0; @@ -295,8 +296,8 @@ namespace WorldPackets uint64 EventID = 0; uint8 Status = 0; bool ClearPending = false; - time_t ResponseTime = time_t(0); - time_t Date = time_t(0); + WowTime ResponseTime; + WowTime Date; ObjectGuid InviteGuid; }; @@ -334,7 +335,7 @@ namespace WorldPackets WorldPacket const* Write() override; uint64 EventID = 0; - time_t Date = time_t(0); + WowTime Date; uint32 Flags = 0; uint8 Status = 0; }; @@ -356,10 +357,10 @@ namespace WorldPackets uint64 EventClubID = 0; uint64 EventID = 0; - time_t Date = time_t(0); + WowTime Date; uint32 Flags = 0; - time_t LockDate = time_t(0); - time_t OriginalDate = time_t(0); + WowTime LockDate; + WowTime OriginalDate; int32 TextureID = 0; uint8 EventType = 0; bool ClearPending = false; @@ -375,7 +376,7 @@ namespace WorldPackets WorldPacket const* Write() override; uint64 EventID = 0; - time_t Date = time_t(0); + WowTime Date; bool ClearPending = false; }; @@ -509,7 +510,7 @@ namespace WorldPackets WorldPacket const* Write() override; - time_t ServerTime = 0; + WowTime ServerTime; int32 MapID = 0; uint32 DifficultyID = 0; int32 NewTimeRemaining = 0; @@ -543,7 +544,7 @@ namespace WorldPackets uint64 EventID = 0; uint32 Flags = 0; - time_t Date = time_t(0); + WowTime Date; uint8 Status = 0; }; diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index aa59ebfc986..fe80b31595d 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -64,7 +64,7 @@ WorldPacket const* WorldPackets::Guild::QueryGuildInfoResponse::Write() WorldPacket const* WorldPackets::Guild::GuildRoster::Write() { _worldPacket << int32(NumAccounts); - _worldPacket.AppendPackedTime(CreateDate); + _worldPacket << CreateDate; _worldPacket << int32(GuildFlags); _worldPacket << uint32(MemberData.size()); _worldPacket.WriteBits(WelcomeText.length(), 11); @@ -871,7 +871,7 @@ void WorldPackets::Guild::GuildQueryNews::Read() ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Guild::GuildNewsEvent const& newsEvent) { data << int32(newsEvent.Id); - data.AppendPackedTime(newsEvent.CompletedDate); + data << newsEvent.CompletedDate; data << int32(newsEvent.Type); data << int32(newsEvent.Flags); diff --git a/src/server/game/Server/Packets/GuildPackets.h b/src/server/game/Server/Packets/GuildPackets.h index bd80498061e..31f9c6ba62d 100644 --- a/src/server/game/Server/Packets/GuildPackets.h +++ b/src/server/game/Server/Packets/GuildPackets.h @@ -24,6 +24,7 @@ #include "MythicPlusPacketsCommon.h" #include "ObjectGuid.h" #include "PacketUtilities.h" +#include "WowTime.h" namespace WorldPackets { @@ -130,7 +131,7 @@ namespace WorldPackets std::vector<GuildRosterMemberData> MemberData; std::string WelcomeText; std::string InfoText; - uint32 CreateDate = 0; + WowTime CreateDate; int32 NumAccounts = 0; int32 GuildFlags = 0; }; @@ -1073,7 +1074,7 @@ namespace WorldPackets struct GuildNewsEvent { int32 Id = 0; - uint32 CompletedDate = 0; + WowTime CompletedDate; int32 Type = 0; int32 Flags = 0; std::array<int32, 2> Data = { }; diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index 9c6687075af..21395173965 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -36,8 +36,8 @@ WorldPacket const* WorldPackets::Misc::InvalidatePlayer::Write() WorldPacket const* WorldPackets::Misc::LoginSetTimeSpeed::Write() { - _worldPacket.AppendPackedTime(ServerTime); - _worldPacket.AppendPackedTime(GameTime); + _worldPacket << ServerTime; + _worldPacket << GameTime; _worldPacket << float(NewSpeed); _worldPacket << uint32(ServerTimeHolidayOffset); _worldPacket << uint32(GameTimeHolidayOffset); diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index ef5de8330d6..b1469847788 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -28,6 +28,7 @@ #include "Player.h" #include "Position.h" #include "SharedDefines.h" +#include "WowTime.h" #include <array> #include <map> @@ -81,8 +82,8 @@ namespace WorldPackets float NewSpeed = 0.0f; int32 ServerTimeHolidayOffset = 0; - uint32 GameTime = 0; - uint32 ServerTime = 0; + WowTime GameTime; + WowTime ServerTime; int32 GameTimeHolidayOffset = 0; }; diff --git a/src/server/game/Server/Packets/SystemPackets.h b/src/server/game/Server/Packets/SystemPackets.h index 5c173e7d3ac..afb0600db98 100644 --- a/src/server/game/Server/Packets/SystemPackets.h +++ b/src/server/game/Server/Packets/SystemPackets.h @@ -234,9 +234,9 @@ namespace WorldPackets WorldPacket const* Write() override; - std::string ServerTimeTZ; - std::string GameTimeTZ; - std::string ServerRegionalTZ; + std::string_view ServerTimeTZ; + std::string_view GameTimeTZ; + std::string_view ServerRegionalTZ; }; } } diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index c4c46c044d9..2f4a333529f 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -106,7 +106,7 @@ bool WorldSessionFilter::Process(WorldPacket* packet) /// WorldSession constructor WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, - std::string os, LocaleConstant locale, uint32 recruiter, bool isARecruiter): + std::string os, Minutes timezoneOffset, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), @@ -118,7 +118,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun _battlenetAccountId(battlenetAccountId), m_accountExpansion(expansion), m_expansion(std::min<uint8>(expansion, sWorld->getIntConfig(CONFIG_EXPANSION))), - _os(os), + _os(std::move(os)), _battlenetRequestToken(0), _logoutTime(0), m_inQueue(false), @@ -127,6 +127,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun m_playerSave(false), m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(locale), + _timezoneOffset(timezoneOffset), m_latency(0), _tutorialsChanged(TUTORIALS_FLAG_NONE), _filterAddonMessages(false), @@ -153,7 +154,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, uint32 battlenetAccoun LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = {};", GetAccountId()); // One-time query } - m_Socket[CONNECTION_TYPE_REALM] = sock; + m_Socket[CONNECTION_TYPE_REALM] = std::move(sock); _instanceConnectKey.Raw = UI64LIT(0); } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 2971a6f59ef..296eda86e61 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -948,7 +948,7 @@ class TC_GAME_API WorldSession { public: WorldSession(uint32 id, std::string&& name, uint32 battlenetAccountId, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, - std::string os, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + std::string os, Minutes timezoneOffset, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return !m_playerLoading.IsEmpty(); } @@ -1131,6 +1131,9 @@ class TC_GAME_API WorldSession // Locales LocaleConstant GetSessionDbcLocale() const { return m_sessionDbcLocale; } LocaleConstant GetSessionDbLocaleIndex() const { return m_sessionDbLocaleIndex; } + + Minutes GetTimezoneOffset() const { return _timezoneOffset; } + char const* GetTrinityString(uint32 entry) const; uint32 GetLatency() const { return m_latency; } @@ -1916,6 +1919,7 @@ class TC_GAME_API WorldSession bool m_playerSave; LocaleConstant m_sessionDbcLocale; LocaleConstant m_sessionDbLocaleIndex; + Minutes _timezoneOffset; std::atomic<uint32> m_latency; AccountData _accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 _tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index c92b8d03c8f..0161974879a 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -626,6 +626,7 @@ struct AccountInfo int64 MuteTime; uint32 Recruiter; std::string OS; + Minutes TimezoneOffset; bool IsRectuiter; AccountTypes Security; bool IsBanned; @@ -633,11 +634,11 @@ struct AccountInfo bool IsBanned() const { return BattleNet.IsBanned || Game.IsBanned; } - explicit AccountInfo(Field* fields) + explicit AccountInfo(Field const* fields) { - // 0 1 2 3 4 5 6 7 8 9 10 11 - // SELECT a.id, a.session_key, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, ba.id, aa.SecurityLevel, - // 12 13 14 + // 0 1 2 3 4 5 6 7 8 9 10 11 12 + // SELECT a.id, a.session_key, ba.last_ip, ba.locked, ba.lock_country, a.expansion, a.mutetime, ba.locale, a.recruiter, a.os, a.timezone_offset, ba.id, aa.SecurityLevel, + // 13 14 15 // bab.unbandate > UNIX_TIMESTAMP() OR bab.unbandate = bab.bandate, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id // FROM account a LEFT JOIN battlenet_accounts ba ON a.battlenet_account = ba.id LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) // LEFT JOIN battlenet_account_bans bab ON ba.id = bab.id LEFT JOIN account_banned ab ON a.id = ab.id LEFT JOIN account r ON a.id = r.recruiter @@ -652,11 +653,12 @@ struct AccountInfo BattleNet.Locale = LocaleConstant(fields[7].GetUInt8()); Game.Recruiter = fields[8].GetUInt32(); Game.OS = fields[9].GetString(); - BattleNet.Id = fields[10].GetUInt32(); - Game.Security = AccountTypes(fields[11].GetUInt8()); - BattleNet.IsBanned = fields[12].GetUInt32() != 0; - Game.IsBanned = fields[13].GetUInt32() != 0; - Game.IsRectuiter = fields[14].GetUInt32() != 0; + Game.TimezoneOffset = Minutes(fields[10].GetInt16()); + BattleNet.Id = fields[11].GetUInt32(); + Game.Security = AccountTypes(fields[12].GetUInt8()); + BattleNet.IsBanned = fields[13].GetUInt32() != 0; + Game.IsBanned = fields[14].GetUInt32() != 0; + Game.IsRectuiter = fields[15].GetUInt32() != 0; if (BattleNet.Locale >= TOTAL_LOCALES) BattleNet.Locale = LOCALE_enUS; @@ -670,7 +672,10 @@ void WorldSocket::HandleAuthSession(std::shared_ptr<WorldPackets::Auth::AuthSess stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->RealmJoinTicket); - _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&WorldSocket::HandleAuthSessionCallback, this, authSession, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback([this, authSession = std::move(authSession)](PreparedQueryResult result) mutable + { + HandleAuthSessionCallback(std::move(authSession), std::move(result)); + })); } void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth::AuthSession> authSession, PreparedQueryResult result) @@ -868,7 +873,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<WorldPackets::Auth:: _authed = true; _worldSession = new WorldSession(account.Game.Id, std::move(authSession->RealmJoinTicket), account.BattleNet.Id, shared_from_this(), account.Game.Security, - account.Game.Expansion, mutetime, account.Game.OS, account.BattleNet.Locale, account.Game.Recruiter, account.Game.IsRectuiter); + account.Game.Expansion, mutetime, account.Game.OS, account.Game.TimezoneOffset, account.BattleNet.Locale, account.Game.Recruiter, account.Game.IsRectuiter); // Initialize Warden system only if it is enabled by config if (wardenActive) diff --git a/src/server/game/Services/WorldserverService.cpp b/src/server/game/Services/WorldserverService.cpp index 61a13011f4b..213ffbbad8f 100644 --- a/src/server/game/Services/WorldserverService.cpp +++ b/src/server/game/Services/WorldserverService.cpp @@ -126,7 +126,7 @@ uint32 Battlenet::GameUtilitiesService::HandleRealmJoinRequest(std::unordered_ma { if (Variant const* realmAddress = GetParam(params, "Param_RealmAddress")) return sRealmList->JoinRealm(uint32(realmAddress->uint_value()), realm.Build, Trinity::Net::make_address(_session->GetRemoteAddress()), _session->GetRealmListSecret(), - _session->GetSessionDbcLocale(), _session->GetOS(), _session->GetAccountName(), response); + _session->GetSessionDbcLocale(), _session->GetOS(), _session->GetTimezoneOffset(), _session->GetAccountName(), response); return ERROR_WOW_SERVICES_INVALID_JOIN_TICKET; } diff --git a/src/server/game/Time/GameTime.cpp b/src/server/game/Time/GameTime.cpp index 399be3196b3..3175c0e5571 100644 --- a/src/server/game/Time/GameTime.cpp +++ b/src/server/game/Time/GameTime.cpp @@ -17,7 +17,9 @@ #include "GameTime.h" #include "Timer.h" +#include "Timezone.h" #include "Util.h" +#include "WowTime.h" namespace GameTime { @@ -31,6 +33,9 @@ namespace GameTime tm DateTime; + WowTime UtcWow; + WowTime Wow; + time_t GetStartTime() { return StartTime; @@ -84,6 +89,16 @@ namespace GameTime return &DateTime; } + WowTime const* GetUtcWowTime() + { + return &UtcWow; + } + + WowTime const* GetWowTime() + { + return &Wow; + } + void UpdateGameTimers() { GameTime = time(nullptr); @@ -91,5 +106,7 @@ namespace GameTime GameTimeSystemPoint = std::chrono::system_clock::now(); GameTimeSteadyPoint = std::chrono::steady_clock::now(); localtime_r(&GameTime, &DateTime); + UtcWow.SetUtcTimeFromUnixTime(GameTime); + Wow = UtcWow + Trinity::Timezone::GetSystemZoneOffsetAt(GameTimeSystemPoint); } } diff --git a/src/server/game/Time/GameTime.h b/src/server/game/Time/GameTime.h index 4229872e016..7b18b030d2c 100644 --- a/src/server/game/Time/GameTime.h +++ b/src/server/game/Time/GameTime.h @@ -21,6 +21,8 @@ #include "Define.h" #include "Duration.h" +class WowTime; + namespace GameTime { // Server start time @@ -47,6 +49,10 @@ namespace GameTime TC_GAME_API tm const* GetDateAndTime(); + TC_GAME_API WowTime const* GetUtcWowTime(); + + TC_GAME_API WowTime const* GetWowTime(); + void UpdateGameTimers(); } diff --git a/src/server/game/Time/WowTime.cpp b/src/server/game/Time/WowTime.cpp new file mode 100644 index 00000000000..b88f0c56a8e --- /dev/null +++ b/src/server/game/Time/WowTime.cpp @@ -0,0 +1,219 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include "WowTime.h" +#include "ByteBuffer.h" +#include "Errors.h" +#include "Util.h" + +uint32 WowTime::GetPackedTime() const +{ + return ((_year % 100) & 0x1F) << 24 + | (_month & 0xF) << 20 + | (_monthDay & 0x3F) << 14 + | (_weekDay & 0x7) << 11 + | (_hour & 0x1F) << 6 + | (_minute & 0x3F) + | (_flags & 0x3) << 29; +} + +void WowTime::SetPackedTime(uint32 packedTime) +{ + _year = (packedTime >> 24) & 0x1F; + if (_year == 31) + _year = -1; + + _month = (packedTime >> 20) & 0xF; + if (_month == 15) + _month = -1; + + _monthDay = (packedTime >> 14) & 0x3F; + if (_monthDay == 63) + _monthDay = -1; + + _weekDay = (packedTime >> 11) & 0x7; + if (_weekDay == 7) + _weekDay = -1; + + _hour = (packedTime >> 6) & 0x1F; + if (_hour == 31) + _hour = -1; + + _minute = packedTime & 0x3F; + if (_minute == 63) + _minute = -1; + + _flags = (packedTime >> 29) & 0x3; + if (_flags == 3) + _flags = -1; +} + +std::time_t WowTime::GetUnixTimeFromUtcTime() const +{ + if (_year < 0 || _month < 0 || _monthDay < 0) + return 0; + + std::tm buf{}; + buf.tm_year = _year + 100; + buf.tm_mon = _month; + buf.tm_mday = _monthDay + 1; + if (_hour >= 0) + { + buf.tm_hour = _hour; + if (_minute >= 0) + buf.tm_min = _minute; + } + buf.tm_isdst = -1; + buf.tm_wday = _weekDay; + + return timegm(&buf); +} + +void WowTime::SetUtcTimeFromUnixTime(std::time_t unixTime) +{ + std::tm buf; + if (!::gmtime_r(&unixTime, &buf)) + return; + + _year = (buf.tm_year - 100) % 100; + _month = buf.tm_mon; + _monthDay = buf.tm_mday - 1; + _weekDay = buf.tm_wday; + _hour = buf.tm_hour; + _minute = buf.tm_min; +} + +void WowTime::SetYear(int32 year) +{ + ASSERT(year == -1 || (year >= 0 && year < 32)); + _year = year; +} + +void WowTime::SetMonth(int8 month) +{ + ASSERT(month == -1 || (month >= 0 && month < 12)); + _month = month; +} + +void WowTime::SetMonthDay(int8 monthDay) +{ + ASSERT(monthDay == -1 || (monthDay >= 0 && monthDay < 32)); + _monthDay = monthDay; +} + +void WowTime::SetWeekDay(int8 weekDay) +{ + ASSERT(weekDay == -1 || (weekDay >= 0 && weekDay < 7)); + _weekDay = weekDay; +} + +void WowTime::SetHour(int8 hour) +{ + ASSERT(hour == -1 || (hour >= 0 && hour < 24)); + _hour = hour; +} + +void WowTime::SetMinute(int8 minute) +{ + ASSERT(minute == -1 || (minute >= 0 && minute < 60)); + _minute = minute; +} + +void WowTime::SetFlags(int8 flags) +{ + ASSERT(flags == -1 || (flags >= 0 && flags < 3)); + _flags = flags; +} + +std::strong_ordering operator<=>(WowTime const& left, WowTime const& right) +{ + auto compareFieldIfSet = [&]<typename T>(T WowTime::*field) -> std::strong_ordering + { + if (left.*field < 0 || right.*field < 0) + return std::strong_ordering::equal; + + return left.*field <=> right.*field; + }; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_year); advstd::is_neq(cmp)) + return cmp; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_month); advstd::is_neq(cmp)) + return cmp; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_monthDay); advstd::is_neq(cmp)) + return cmp; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_weekDay); advstd::is_neq(cmp)) + return cmp; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_year); advstd::is_neq(cmp)) + return cmp; + + if (std::strong_ordering cmp = compareFieldIfSet(&WowTime::_hour); advstd::is_neq(cmp)) + return cmp; + + return std::strong_ordering::equal; +} + +bool WowTime::IsInRange(WowTime const& from, WowTime const& to) const +{ + if (from > to) + return *this >= from || *this < to; + + return *this >= from && *this < to; +} + +WowTime& WowTime::operator+=(Seconds seconds) +{ + time_t unixTime = GetUnixTimeFromUtcTime(); + unixTime += seconds.count(); + SetUtcTimeFromUnixTime(unixTime); + return *this; +} + +WowTime WowTime::operator+(Seconds seconds) const +{ + return WowTime(*this) += seconds; +} + +WowTime& WowTime::operator-=(Seconds seconds) +{ + time_t unixTime = GetUnixTimeFromUtcTime(); + unixTime -= seconds.count(); + SetUtcTimeFromUnixTime(unixTime); + return *this; +} + +WowTime WowTime::operator-(Seconds seconds) const +{ + return WowTime(*this) -= seconds; +} + +ByteBuffer& operator<<(ByteBuffer& data, WowTime const& wowTime) +{ + data << uint32(wowTime.GetPackedTime()); + return data; +} + +ByteBuffer& operator>>(ByteBuffer& data, WowTime& wowTime) +{ + uint32 packedTime = 0; + data >> packedTime; + wowTime.SetPackedTime(packedTime); + return data; +} diff --git a/src/server/game/Time/WowTime.h b/src/server/game/Time/WowTime.h new file mode 100644 index 00000000000..a273d210d6a --- /dev/null +++ b/src/server/game/Time/WowTime.h @@ -0,0 +1,90 @@ +/* + * This file is part of the TrinityCore Project. See AUTHORS file for Copyright information + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the + * Free Software Foundation; either version 2 of the License, or (at your + * option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for + * more details. + * + * You should have received a copy of the GNU General Public License along + * with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef TRINITYCORE_WOWTIME_H +#define TRINITYCORE_WOWTIME_H + +#include "Define.h" +#include "Duration.h" +#include "advstd.h" +#include <compare> +#include <ctime> + +class ByteBuffer; + +class WowTime +{ +public: + uint32 GetPackedTime() const; + void SetPackedTime(uint32 packedTime); + + std::time_t GetUnixTimeFromUtcTime() const; + void SetUtcTimeFromUnixTime(std::time_t unixTime); + + int32 GetYear() const { return _year; } + void SetYear(int32 year); + + int8 GetMonth() const { return _month; } + void SetMonth(int8 month); + + int8 GetMonthDay() const { return _monthDay; } + void SetMonthDay(int8 monthDay); + + int8 GetWeekDay() const { return _weekDay; } + void SetWeekDay(int8 weekDay); + + int8 GetHour() const { return _hour; } + void SetHour(int8 hour); + + int8 GetMinute() const { return _minute; } + void SetMinute(int8 minute); + + int8 GetFlags() const { return _flags; } + void SetFlags(int8 flags); + + int8 GetHolidayOffset() const { return _holidayOffset; } + void SetHolidayOffset(int8 holidayOffset) { _holidayOffset = holidayOffset; } + + friend TC_GAME_API std::strong_ordering operator<=>(WowTime const& left, WowTime const& right); + friend TC_GAME_API bool operator==(WowTime const& left, WowTime const& right) + { + return advstd::is_eq(left <=> right); + } + + bool IsInRange(WowTime const& from, WowTime const& to) const; + + WowTime& operator+=(Seconds seconds); + WowTime operator+(Seconds seconds) const; + + WowTime& operator-=(Seconds seconds); + WowTime operator-(Seconds seconds) const; + + friend TC_GAME_API ByteBuffer& operator<<(ByteBuffer& data, WowTime const& wowTime); + friend TC_GAME_API ByteBuffer& operator>>(ByteBuffer& data, WowTime& wowTime); + +private: + int32 _year = -1; + int8 _month = -1; + int8 _monthDay = -1; + int8 _weekDay = -1; + int8 _hour = -1; + int8 _minute = -1; + int8 _flags = -1; + int8 _holidayOffset = 0; +}; + +#endif // TRINITYCORE_WOWTIME_H diff --git a/src/server/shared/Packets/ByteBuffer.cpp b/src/server/shared/Packets/ByteBuffer.cpp index 1775192227a..104ba96d9d0 100644 --- a/src/server/shared/Packets/ByteBuffer.cpp +++ b/src/server/shared/Packets/ByteBuffer.cpp @@ -23,7 +23,6 @@ #include <utf8.h> #include <sstream> #include <cmath> -#include <ctime> ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _bitpos(InitialBitPos), _curbitval(0), _storage(buffer.Move()) { @@ -92,21 +91,6 @@ std::string ByteBuffer::ReadString(uint32 length, bool requireValidUtf8 /*= true return value; } -uint32 ByteBuffer::ReadPackedTime() -{ - uint32 packedDate = read<uint32>(); - tm lt = tm(); - - lt.tm_min = packedDate & 0x3F; - lt.tm_hour = (packedDate >> 6) & 0x1F; - //lt.tm_wday = (packedDate >> 11) & 7; - lt.tm_mday = ((packedDate >> 14) & 0x3F) + 1; - lt.tm_mon = (packedDate >> 20) & 0xF; - lt.tm_year = ((packedDate >> 24) & 0x1F) + 100; - - return uint32(mktime(<)); -} - void ByteBuffer::append(uint8 const* src, size_t cnt) { ASSERT(src, "Attempted to put a NULL-pointer in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", _wpos, size()); @@ -134,13 +118,6 @@ void ByteBuffer::append(uint8 const* src, size_t cnt) _wpos = newSize; } -void ByteBuffer::AppendPackedTime(time_t time) -{ - tm lt; - localtime_r(&time, <); - append<uint32>((lt.tm_year - 100) << 24 | lt.tm_mon << 20 | (lt.tm_mday - 1) << 14 | lt.tm_wday << 11 | lt.tm_hour << 6 | lt.tm_min); -} - void ByteBuffer::put(size_t pos, uint8 const* src, size_t cnt) { ASSERT(pos + cnt <= size(), "Attempted to put value with size: " SZFMTD " in ByteBuffer (pos: " SZFMTD " size: " SZFMTD ")", cnt, pos, size()); diff --git a/src/server/shared/Packets/ByteBuffer.h b/src/server/shared/Packets/ByteBuffer.h index 76b521b9358..de0adf54341 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -519,8 +519,6 @@ class TC_SHARED_API ByteBuffer std::string ReadString(uint32 length, bool requireValidUtf8 = true); - uint32 ReadPackedTime(); - uint8* contents() { if (_storage.empty()) @@ -624,8 +622,6 @@ class TC_SHARED_API ByteBuffer return resultSize; } - void AppendPackedTime(time_t time); - void put(size_t pos, uint8 const* src, size_t cnt); void print_storage() const; diff --git a/src/server/shared/Realm/RealmList.cpp b/src/server/shared/Realm/RealmList.cpp index 3d72418c10b..779bb6fca09 100644 --- a/src/server/shared/Realm/RealmList.cpp +++ b/src/server/shared/Realm/RealmList.cpp @@ -369,7 +369,7 @@ std::vector<uint8> RealmList::GetRealmList(uint32 build, std::string const& subR } uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, std::string accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const + LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const { std::shared_lock<std::shared_mutex> lock(_realmsMutex); if (Realm const* realm = GetRealm(Battlenet::RealmHandle(realmAddress))) @@ -400,15 +400,17 @@ uint32 RealmList::JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip:: std::array<uint8, 32> serverSecret = Trinity::Crypto::GetRandomBytes<32>(); std::array<uint8, 64> keyData; - memcpy(&keyData[0], clientSecret.data(), 32); - memcpy(&keyData[32], serverSecret.data(), 32); + auto keyDestItr = keyData.begin(); + keyDestItr = std::copy(clientSecret.begin(), clientSecret.end(), keyDestItr); + keyDestItr = std::copy(serverSecret.begin(), serverSecret.end(), keyDestItr); LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_UPD_BNET_GAME_ACCOUNT_LOGIN_INFO); stmt->setBinary(0, keyData); stmt->setString(1, clientAddress.to_string()); stmt->setUInt8(2, locale); stmt->setString(3, os); - stmt->setString(4, accountName); + stmt->setInt16(4, timezoneOffset.count()); + stmt->setString(5, accountName); LoginDatabase.DirectExecute(stmt); bgs::protocol::Attribute* attribute = response->add_attribute(); diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index 973dd913d7a..a1262d7e913 100644 --- a/src/server/shared/Realm/RealmList.h +++ b/src/server/shared/Realm/RealmList.h @@ -19,6 +19,7 @@ #define _REALMLIST_H #include "Define.h" +#include "Duration.h" #include "Realm.h" #include <array> #include <map> @@ -91,7 +92,8 @@ public: std::vector<uint8> GetRealmEntryJSON(Battlenet::RealmHandle const& id, uint32 build) const; std::vector<uint8> GetRealmList(uint32 build, std::string const& subRegion) const; uint32 JoinRealm(uint32 realmAddress, uint32 build, boost::asio::ip::address const& clientAddress, std::array<uint8, 32> const& clientSecret, - LocaleConstant locale, std::string const& os, std::string accountName, bgs::protocol::game_utilities::v1::ClientResponse* response) const; + LocaleConstant locale, std::string const& os, Minutes timezoneOffset, std::string const& accountName, + bgs::protocol::game_utilities::v1::ClientResponse* response) const; private: RealmList(); |