diff options
41 files changed, 2394 insertions, 805 deletions
diff --git a/dep/boost/CMakeLists.txt b/dep/boost/CMakeLists.txt index 65d5c9355e4..330c14f6d51 100644 --- a/dep/boost/CMakeLists.txt +++ b/dep/boost/CMakeLists.txt @@ -35,7 +35,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 0018c699df4..3e2f026cfb8 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(3) CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci NOT NULL DEFAULT '', + `timezone_offset` smallint NOT NULL DEFAULT '0', `recruiter` int unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`id`), UNIQUE KEY `idx_username` (`username`) @@ -2008,7 +2009,8 @@ INSERT INTO `updates` VALUES ('2023_02_05_00_auth.sql','DC8A2046EB4201D55342C541A0E9C398499E12B1','ARCHIVED','2023-02-05 14:50:30',0), ('2023_02_05_01_auth.sql','336E62A8850A3E78A1D0BD3E81FFD5769184BDF8','ARCHIVED','2023-02-05 15:58:32',0), ('2023_05_05_00_auth.sql','DEEB1D5533658E3479FC3C988EF4B9816C511BC3','ARCHIVED','2023-05-07 11:52:00',0), -('2023_06_14_00_auth.sql','BB8A7EB214F4F3632C4F54EA596CB7C8FBA305D5','ARCHIVED','2023-06-14 19:34:24',0); +('2023_06_14_00_auth.sql','BB8A7EB214F4F3632C4F54EA596CB7C8FBA305D5','ARCHIVED','2023-06-14 19:34:24',0), +('2023_11_21_00_auth.sql','146E5E6EF94C5DB78343372A8FDB32B062B80040','RELEASED','2023-11-21 11:24:11',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 89fa2a0ef1a..89fa2a0ef1a 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..6bc5773edc3 --- /dev/null +++ b/src/common/Time/Timezone.cpp @@ -0,0 +1,180 @@ +/* + * 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 "StringConvert.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..3515617ab13 --- /dev/null +++ b/src/common/Time/Timezone.h @@ -0,0 +1,38 @@ +/* + * 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" +#include <string> + +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 0486d338a70..5aa3ba05331 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 9c77e9f9821..8ca639ba6a4 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 62c8655b65f..14d633e2ae8 100644 --- a/src/common/Utilities/Util.h +++ b/src/common/Utilities/Util.h @@ -51,8 +51,11 @@ namespace Trinity TC_COMMON_API Optional<int32> 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 time_t LocalTimeToUTCTime(time_t time); +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 GetLocalHourTimestamp(time_t time, uint8 hour, bool onlyAfterTime = true); TC_COMMON_API tm TimeBreakdown(time_t t); diff --git a/src/server/authserver/Server/AuthSession.cpp b/src/server/authserver/Server/AuthSession.cpp index d9058b3392a..ba2ef766ac7 100644 --- a/src/server/authserver/Server/AuthSession.cpp +++ b/src/server/authserver/Server/AuthSession.cpp @@ -18,21 +18,19 @@ #include "AuthSession.h" #include "AES.h" #include "AuthCodes.h" +#include "ByteBuffer.h" #include "Config.h" #include "CryptoGenerics.h" +#include "CryptoHash.h" #include "CryptoRandom.h" #include "DatabaseEnv.h" -#include "Errors.h" -#include "CryptoHash.h" #include "IPLocation.h" #include "Log.h" #include "RealmList.h" #include "SecretMgr.h" -#include "Timer.h" #include "TOTP.h" #include "Util.h" #include <boost/lexical_cast.hpp> -#include <openssl/crypto.h> using boost::asio::ip::tcp; @@ -161,7 +159,7 @@ void AccountInfo::LoadResult(Field* fields) } AuthSession::AuthSession(tcp::socket&& socket) : Socket(std::move(socket)), -_status(STATUS_CHALLENGE), _build(0), _expversion(0) { } +_status(STATUS_CHALLENGE), _build(0), _timezoneOffset(0min), _expversion(0) { } void AuthSession::Start() { @@ -300,11 +298,14 @@ bool AuthSession::HandleLogonChallenge() for (int i = 0; i < 4; ++i) _localizationName[i] = challenge->country[4 - i - 1]; + _timezoneOffset = Minutes(challenge->timezone_bias); + // Get the account details from the account table LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_LOGONCHALLENGE); stmt->setString(0, login); - _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::LogonChallengeCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt) + .WithPreparedCallback([this](PreparedQueryResult result) { LogonChallengeCallback(std::move(result)); })); return true; } @@ -513,7 +514,8 @@ bool AuthSession::HandleLogonProof() stmt->setString(1, address); stmt->setUInt32(2, GetLocaleByName(_localizationName)); stmt->setString(3, _os); - stmt->setString(4, _accountInfo.Login); + stmt->setInt16(4, _timezoneOffset.count()); + stmt->setString(5, _accountInfo.Login); LoginDatabase.DirectExecute(stmt); // Finish SRP6 and send the final result to the client @@ -636,11 +638,14 @@ bool AuthSession::HandleReconnectChallenge() for (int i = 0; i < 4; ++i) _localizationName[i] = challenge->country[4 - i - 1]; + _timezoneOffset = Minutes(challenge->timezone_bias); + // Get the account details from the account table LoginDatabasePreparedStatement* stmt = LoginDatabase.GetPreparedStatement(LOGIN_SEL_RECONNECTCHALLENGE); stmt->setString(0, login); - _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt).WithPreparedCallback(std::bind(&AuthSession::ReconnectChallengeCallback, this, std::placeholders::_1))); + _queryProcessor.AddCallback(LoginDatabase.AsyncQuery(stmt) + .WithPreparedCallback([this](PreparedQueryResult result) { ReconnectChallengeCallback(std::move(result)); })); return true; } diff --git a/src/server/authserver/Server/AuthSession.h b/src/server/authserver/Server/AuthSession.h index 71af8272501..844de0ed787 100644 --- a/src/server/authserver/Server/AuthSession.h +++ b/src/server/authserver/Server/AuthSession.h @@ -19,20 +19,18 @@ #define __AUTHSESSION_H__ #include "AsyncCallbackProcessor.h" -#include "BigNumber.h" -#include "ByteBuffer.h" #include "Common.h" #include "CryptoHash.h" +#include "DatabaseEnvFwd.h" +#include "Duration.h" #include "Optional.h" #include "Socket.h" #include "SRP6.h" -#include "QueryResult.h" -#include <memory> #include <boost/asio/ip/tcp.hpp> using boost::asio::ip::tcp; -class Field; +class ByteBuffer; struct AuthHandler; enum AuthStatus @@ -102,6 +100,7 @@ private: std::string _os; std::string _ipCountry; uint16 _build; + Minutes _timezoneOffset; uint8 _expversion; QueryCallbackProcessor _queryProcessor; diff --git a/src/server/database/Database/Implementation/LoginDatabase.cpp b/src/server/database/Database/Implementation/LoginDatabase.cpp index 6939c2120aa..71023e8e9e2 100644 --- a/src/server/database/Database/Implementation/LoginDatabase.cpp +++ b/src/server/database/Database/Implementation/LoginDatabase.cpp @@ -36,7 +36,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_INS_ACCOUNT_AUTO_BANNED, "INSERT INTO account_banned (id, bandate, unbandate, bannedby, banreason, active) VALUES (?, UNIX_TIMESTAMP(), UNIX_TIMESTAMP()+?, 'Trinity Auth', 'Failed login autoban', 1)", CONNECTION_ASYNC); PrepareStatement(LOGIN_DEL_ACCOUNT_BANNED, "DELETE FROM account_banned WHERE id = ?", CONNECTION_ASYNC); PrepareStatement(LOGIN_UPD_LOGON, "UPDATE account SET salt = ?, verifier = ? WHERE id = ?", CONNECTION_ASYNC); - PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET session_key_auth = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ? WHERE username = ?", CONNECTION_SYNCH); + PrepareStatement(LOGIN_UPD_LOGONPROOF, "UPDATE account SET session_key_auth = ?, last_ip = ?, last_login = NOW(), locale = ?, failed_logins = 0, os = ?, timezone_offset = ? WHERE username = ?", CONNECTION_SYNCH); PrepareStatement(LOGIN_SEL_LOGONCHALLENGE, "SELECT a.id, a.username, a.locked, a.lock_country, a.last_ip, a.failed_logins, ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, " "ab.unbandate = ab.bandate, aa.SecurityLevel, a.totp_secret, a.salt, a.verifier " "FROM account a LEFT JOIN account_access aa ON a.id = aa.AccountID LEFT JOIN account_banned ab ON ab.id = a.id AND ab.active = 1 WHERE a.username = ?", CONNECTION_ASYNC); @@ -46,7 +46,7 @@ void LoginDatabaseConnection::DoPrepareStatements() PrepareStatement(LOGIN_UPD_FAILEDLOGINS, "UPDATE account SET failed_logins = failed_logins + 1 WHERE username = ?", 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_auth, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, aa.SecurityLevel, " + PrepareStatement(LOGIN_SEL_ACCOUNT_INFO_BY_NAME, "SELECT a.id, a.session_key_auth, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, a.timezone_offset, aa.SecurityLevel, " "ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id FROM account a LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) " "LEFT JOIN account_banned ab ON a.id = ab.id AND ab.active = 1 LEFT JOIN account r ON a.id = r.recruiter WHERE a.username = ? AND a.session_key_auth IS NOT NULL ORDER BY aa.RealmID DESC LIMIT 1", CONNECTION_ASYNC); PrepareStatement(LOGIN_SEL_ACCOUNT_LIST_BY_EMAIL, "SELECT id, username FROM account WHERE email = ?", CONNECTION_SYNCH); diff --git a/src/server/game/Achievements/AchievementMgr.cpp b/src/server/game/Achievements/AchievementMgr.cpp index 5db2f3dcc6c..a7c9960abf9 100644 --- a/src/server/game/Achievements/AchievementMgr.cpp +++ b/src/server/game/Achievements/AchievementMgr.cpp @@ -44,6 +44,7 @@ #include "SpellMgr.h" #include "World.h" #include "WorldSession.h" +#include "WowTime.h" bool AchievementCriteriaData::IsValid(AchievementCriteriaEntry const* criteria) { @@ -705,16 +706,30 @@ void AchievementMgr::SendAchievementEarned(AchievementEntry const* achievement) Cell::VisitWorldObjects(GetPlayer(), _worker, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY)); } - WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8+4+8); - data << GetPlayer()->GetPackGUID(); - data << uint32(achievement->ID); - data.AppendPackedTime(GameTime::GetGameTime()); - data << uint32(0); - GetPlayer()->SendMessageToSetInRange(&data, sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY), true); + auto achievementEarnedBuilder = [&](Player const* receiver) + { + WowTime now = *GameTime::GetUtcWowTime(); + now += receiver->GetSession()->GetTimezoneOffset(); + + WorldPacket data(SMSG_ACHIEVEMENT_EARNED, 8 + 4 + 8); + data << GetPlayer()->GetPackGUID(); + data << uint32(achievement->ID); + data << now; + data << uint32(0); + receiver->SendDirectMessage(&data); + }; + + float dist = sWorld->getFloatConfig(CONFIG_LISTEN_RANGE_SAY); + Trinity::PlayerDistWorker notifier(GetPlayer(), dist, achievementEarnedBuilder); + Cell::VisitWorldObjects(GetPlayer(), notifier, dist); } void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, CriteriaProgress const* progress, uint32 timeElapsed, bool timedCompleted) const { + WowTime date; + date.SetUtcTimeFromUnixTime(progress->date); + date += GetPlayer()->GetSession()->GetTimezoneOffset(); + WorldPacket data(SMSG_CRITERIA_UPDATE, 8 + 4 + 8); data << uint32(entry->ID); @@ -726,7 +741,7 @@ void AchievementMgr::SendCriteriaUpdate(AchievementCriteriaEntry const* entry, C data << uint32(0); else data << uint32(timedCompleted ? 1 : 0); // this are some flags, 1 is for keeping the counter at 0 in client - data.AppendPackedTime(progress->date); + data << date; data << uint32(timeElapsed); // time elapsed in seconds data << uint32(0); // unk GetPlayer()->SendDirectMessage(&data); @@ -1575,7 +1590,7 @@ void AchievementMgr::CompletedAchievement(AchievementEntry const* achievement) void AchievementMgr::SendAllAchievementData() const { WorldPacket data(SMSG_ALL_ACHIEVEMENT_DATA, m_completedAchievements.size() * 8 + 4 + m_criteriaProgress.size() * 38 + 4); - BuildAllDataPacket(&data); + BuildAllDataPacket(GetPlayer(), &data); GetPlayer()->SendDirectMessage(&data); } @@ -1583,14 +1598,14 @@ void AchievementMgr::SendRespondInspectAchievements(Player* player) const { WorldPacket data(SMSG_RESPOND_INSPECT_ACHIEVEMENTS, 9 + m_completedAchievements.size() * 8 + 4 + m_criteriaProgress.size() * 38 + 4); data << GetPlayer()->GetPackGUID(); - BuildAllDataPacket(&data); + BuildAllDataPacket(player, &data); player->SendDirectMessage(&data); } /** * used by SMSG_RESPOND_INSPECT_ACHIEVEMENT and SMSG_ALL_ACHIEVEMENT_DATA */ -void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const +void AchievementMgr::BuildAllDataPacket(Player const* receiver, WorldPacket* data) const { for (std::pair<uint32 const, CompletedAchievementData> const& completedAchievement : m_completedAchievements) { @@ -1599,18 +1614,26 @@ void AchievementMgr::BuildAllDataPacket(WorldPacket* data) const if (!achievement || achievement->Flags & ACHIEVEMENT_FLAG_HIDDEN) continue; + WowTime date; + date.SetUtcTimeFromUnixTime(completedAchievement.second.date); + date += receiver->GetSession()->GetTimezoneOffset(); + *data << uint32(completedAchievement.first); - data->AppendPackedTime(completedAchievement.second.date); + *data << date; } *data << int32(-1); for (std::pair<uint32 const, CriteriaProgress> const& criteriaProgress : m_criteriaProgress) { + WowTime date; + date.SetUtcTimeFromUnixTime(criteriaProgress.second.date); + date += receiver->GetSession()->GetTimezoneOffset(); + *data << uint32(criteriaProgress.first); data->appendPackGUID(criteriaProgress.second.counter); *data << GetPlayer()->GetPackGUID(); *data << uint32(0); - data->AppendPackedTime(criteriaProgress.second.date); + *data << date; *data << uint32(0); *data << uint32(0); } diff --git a/src/server/game/Achievements/AchievementMgr.h b/src/server/game/Achievements/AchievementMgr.h index 1daaf0b3703..28041c35e77 100644 --- a/src/server/game/Achievements/AchievementMgr.h +++ b/src/server/game/Achievements/AchievementMgr.h @@ -302,7 +302,7 @@ class TC_GAME_API AchievementMgr bool IsCompletedCriteria(AchievementCriteriaEntry const* achievementCriteria, AchievementEntry const* achievement); bool IsCompletedAchievement(AchievementEntry const* entry); bool CanUpdateCriteria(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref); - void BuildAllDataPacket(WorldPacket* data) const; + void BuildAllDataPacket(Player const* receiver, WorldPacket* data) const; bool ConditionsSatisfied(AchievementCriteriaEntry const* criteria) const; bool RequirementsSatisfied(AchievementCriteriaEntry const* criteria, AchievementEntry const* achievement, uint32 miscValue1, uint32 miscValue2, WorldObject const* ref) const; diff --git a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp index a05e4a0b5b1..a797cc2c8de 100644 --- a/src/server/game/AuctionHouse/AuctionHouseMgr.cpp +++ b/src/server/game/AuctionHouse/AuctionHouseMgr.cpp @@ -31,11 +31,10 @@ #include "ObjectAccessor.h" #include "ObjectMgr.h" #include "Player.h" -#include "Realm.h" #include "ScriptMgr.h" #include "World.h" -#include "WorldPacket.h" #include "WorldSession.h" +#include "WowTime.h" enum eAuctionHouse { @@ -195,12 +194,13 @@ void AuctionHouseMgr::SendAuctionSalePendingMail(AuctionEntry* auction, Characte // owner exist (online or offline) if ((owner || owner_accId) && !sAuctionBotConfig->IsBotChar(auction->owner)) { - ByteBuffer timePacker; - timePacker.AppendPackedTime(GameTime::GetGameTime() + sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY)); + WowTime eta = *GameTime::GetUtcWowTime(); + eta += Seconds(sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY)); + eta += owner->GetSession()->GetTimezoneOffset(); MailDraft(auction->BuildAuctionMailSubject(AUCTION_SALE_PENDING), AuctionEntry::BuildAuctionInvoiceMailBody(ObjectGuid::Create<HighGuid::Player>(auction->bidder), auction->bid, auction->buyout, auction->deposit, - auction->GetAuctionCut(), sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), timePacker.read<uint32>())) + auction->GetAuctionCut(), sWorld->getIntConfig(CONFIG_MAIL_DELIVERY_DELAY), eta.GetPackedTime())) .SendMailTo(trans, MailReceiver(owner, auction->owner), auction, MAIL_CHECK_MASK_COPIED); } } diff --git a/src/server/game/Battlegrounds/ArenaTeam.cpp b/src/server/game/Battlegrounds/ArenaTeam.cpp index ed14ea64729..f9901f3c422 100644 --- a/src/server/game/Battlegrounds/ArenaTeam.cpp +++ b/src/server/game/Battlegrounds/ArenaTeam.cpp @@ -18,6 +18,7 @@ #include "ArenaTeam.h" #include "ArenaTeamMgr.h" #include "BattlegroundMgr.h" +#include "CalendarPackets.h" #include "CharacterCache.h" #include "DatabaseEnv.h" #include "Group.h" @@ -27,7 +28,6 @@ #include "ObjectMgr.h" #include "Player.h" #include "World.h" -#include "WorldPacket.h" #include "WorldSession.h" ArenaTeam::ArenaTeam() @@ -581,19 +581,13 @@ void ArenaTeam::BroadcastEvent(ArenaTeamEvents event, ObjectGuid guid, uint8 str void ArenaTeam::MassInviteToEvent(WorldSession* session) { - WorldPacket data(SMSG_CALENDAR_ARENA_TEAM, (Members.size() - 1) * (4 + 8 + 1)); - data << uint32(Members.size() - 1); + WorldPackets::Calendar::CalendarEventInitialInvites packet(false); - for (MemberList::const_iterator itr = Members.begin(); itr != Members.end(); ++itr) - { - if (itr->Guid != session->GetPlayer()->GetGUID()) - { - data << itr->Guid.WriteAsPacked(); - data << uint8(0); // unk - } - } + for (ArenaTeamMember const& member : Members) + if (member.Guid != session->GetPlayer()->GetGUID()) + packet.Invites.emplace_back(member.Guid, 0); - session->SendPacket(&data); + session->SendPacket(packet.Write()); } uint8 ArenaTeam::GetSlotByType(uint32 type) diff --git a/src/server/game/Calendar/CalendarMgr.cpp b/src/server/game/Calendar/CalendarMgr.cpp index 535004696ab..3b10ccff017 100644 --- a/src/server/game/Calendar/CalendarMgr.cpp +++ b/src/server/game/Calendar/CalendarMgr.cpp @@ -16,6 +16,7 @@ */ #include "CalendarMgr.h" +#include "CalendarPackets.h" #include "CharacterCache.h" #include "DatabaseEnv.h" #include "GameTime.h" @@ -23,13 +24,15 @@ #include "GuildMgr.h" #include "Log.h" #include "Mail.h" +#include "MapUtils.h" #include "ObjectAccessor.h" -#include "Opcodes.h" #include "Player.h" -#include "WorldPacket.h" +#include "StringConvert.h" +#include "WorldSession.h" +#include "WowTime.h" -CalendarInvite::CalendarInvite() : _inviteId(1), _eventId(0), _invitee(), _senderGUID(), _statusTime(GameTime::GetGameTime()), -_status(CALENDAR_STATUS_INVITED), _rank(CALENDAR_RANK_PLAYER), _text("") { } +CalendarInvite::CalendarInvite() : _inviteId(1), _eventId(0), _invitee(), _senderGUID(), _responseTime(0), +_status(CALENDAR_STATUS_INVITED), _rank(CALENDAR_RANK_PLAYER), _note() { } CalendarInvite::~CalendarInvite() { @@ -75,24 +78,24 @@ void CalendarMgr::LoadFromDB() { Field* fields = result->Fetch(); - uint64 eventId = fields[0].GetUInt64(); - ObjectGuid creatorGUID = ObjectGuid(HighGuid::Player, fields[1].GetUInt32()); + uint64 eventID = fields[0].GetUInt64(); + ObjectGuid ownerGUID = ObjectGuid::Create<HighGuid::Player>(fields[1].GetUInt32()); std::string title = fields[2].GetString(); std::string description = fields[3].GetString(); CalendarEventType type = CalendarEventType(fields[4].GetUInt8()); - int32 dungeonId = fields[5].GetInt32(); - uint32 eventTime = fields[6].GetUInt32(); + int32 textureID = fields[5].GetInt32(); + time_t date = fields[6].GetUInt32(); uint32 flags = fields[7].GetUInt32(); - uint32 timezoneTime = fields[8].GetUInt32(); - ObjectGuid::LowType guildId = 0; + time_t lockDate = fields[8].GetUInt32(); + ObjectGuid::LowType guildID = UI64LIT(0); if (flags & CALENDAR_FLAG_GUILD_EVENT || flags & CALENDAR_FLAG_WITHOUT_INVITES) - guildId = sCharacterCache->GetCharacterGuildIdByGuid(creatorGUID); + guildID = sCharacterCache->GetCharacterGuildIdByGuid(ownerGUID); - CalendarEvent* calendarEvent = new CalendarEvent(eventId, creatorGUID, guildId, type, dungeonId, time_t(eventTime), flags, time_t(timezoneTime), title, description); + CalendarEvent* calendarEvent = new CalendarEvent(eventID, ownerGUID, guildID, type, textureID, date, flags, title, description, lockDate); _events.insert(calendarEvent); - _maxEventId = std::max(_maxEventId, eventId); + _maxEventId = std::max(_maxEventId, eventID); ++count; } @@ -110,14 +113,14 @@ void CalendarMgr::LoadFromDB() uint64 inviteId = fields[0].GetUInt64(); uint64 eventId = fields[1].GetUInt64(); - ObjectGuid invitee = ObjectGuid(HighGuid::Player, fields[2].GetUInt32()); - ObjectGuid senderGUID = ObjectGuid(HighGuid::Player, fields[3].GetUInt32()); + ObjectGuid invitee = ObjectGuid::Create<HighGuid::Player>(fields[2].GetUInt32()); + ObjectGuid senderGUID = ObjectGuid::Create<HighGuid::Player>(fields[3].GetUInt32()); CalendarInviteStatus status = CalendarInviteStatus(fields[4].GetUInt8()); - uint32 statusTime = fields[5].GetUInt32(); + time_t responseTime = fields[5].GetUInt32(); CalendarModerationRank rank = CalendarModerationRank(fields[6].GetUInt8()); - std::string text = fields[7].GetString(); + std::string note = fields[7].GetString(); - CalendarInvite* invite = new CalendarInvite(inviteId, eventId, invitee, senderGUID, time_t(statusTime), status, rank, text); + CalendarInvite* invite = new CalendarInvite(inviteId, eventId, invitee, senderGUID, responseTime, status, rank, note); _invites[eventId].push_back(invite); _maxInviteId = std::max(_maxInviteId, inviteId); @@ -141,7 +144,7 @@ void CalendarMgr::AddEvent(CalendarEvent* calendarEvent, CalendarSendEventType s { _events.insert(calendarEvent); UpdateEvent(calendarEvent); - SendCalendarEvent(calendarEvent->GetCreatorGUID(), *calendarEvent, sendType); + SendCalendarEvent(calendarEvent->GetOwnerGUID(), *calendarEvent, sendType); } void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite, CharacterDatabaseTransaction trans) @@ -149,7 +152,7 @@ void CalendarMgr::AddInvite(CalendarEvent* calendarEvent, CalendarInvite* invite if (!calendarEvent->IsGuildAnnouncement()) SendCalendarEventInvite(*invite); - if (!calendarEvent->IsGuildEvent() || invite->GetInviteeGUID() == calendarEvent->GetCreatorGUID()) + if (!calendarEvent->IsGuildEvent() || invite->GetInviteeGUID() == calendarEvent->GetOwnerGUID()) SendCalendarEventInviteAlert(*calendarEvent, *invite); if (!calendarEvent->IsGuildAnnouncement()) @@ -184,7 +187,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) @@ -196,8 +198,11 @@ 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 && invite->GetInviteeGUID() != remover) + 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; } @@ -252,14 +257,14 @@ void CalendarMgr::UpdateEvent(CalendarEvent* calendarEvent) { CharacterDatabasePreparedStatement* stmt = CharacterDatabase.GetPreparedStatement(CHAR_REP_CALENDAR_EVENT); stmt->setUInt64(0, calendarEvent->GetEventId()); - stmt->setUInt32(1, calendarEvent->GetCreatorGUID().GetCounter()); + stmt->setUInt32(1, calendarEvent->GetOwnerGUID().GetCounter()); stmt->setString(2, calendarEvent->GetTitle()); stmt->setString(3, calendarEvent->GetDescription()); stmt->setUInt8(4, calendarEvent->GetType()); - stmt->setInt32(5, calendarEvent->GetDungeonId()); - stmt->setUInt32(6, uint32(calendarEvent->GetEventTime())); + stmt->setInt32(5, calendarEvent->GetTextureId()); + stmt->setUInt32(6, calendarEvent->GetDate()); stmt->setUInt32(7, calendarEvent->GetFlags()); - stmt->setUInt32(8, calendarEvent->GetTimeZoneTime()); // correct? + stmt->setUInt32(8, calendarEvent->GetLockDate()); CharacterDatabase.Execute(stmt); } @@ -271,9 +276,9 @@ void CalendarMgr::UpdateInvite(CalendarInvite* invite, CharacterDatabaseTransact stmt->setUInt32(2, invite->GetInviteeGUID().GetCounter()); stmt->setUInt32(3, invite->GetSenderGUID().GetCounter()); stmt->setUInt8(4, invite->GetStatus()); - stmt->setUInt32(5, uint32(invite->GetStatusTime())); + stmt->setUInt32(5, invite->GetResponseTime()); stmt->setUInt8(6, invite->GetRank()); - stmt->setString(7, invite->GetText()); + stmt->setString(7, invite->GetNote()); CharacterDatabase.ExecuteOrAppend(trans, stmt); } @@ -283,7 +288,7 @@ void CalendarMgr::RemoveAllPlayerEventsAndInvites(ObjectGuid guid) { CalendarEvent* event = *itr; ++itr; - if (event->GetCreatorGUID() == guid) + if (event->GetOwnerGUID() == guid) RemoveEvent(event, ObjectGuid::Empty); // don't send mail if removing a character } @@ -295,7 +300,7 @@ void CalendarMgr::RemoveAllPlayerEventsAndInvites(ObjectGuid guid) void CalendarMgr::RemovePlayerGuildEventsAndSignups(ObjectGuid guid, ObjectGuid::LowType guildId) { for (CalendarEventStore::const_iterator itr = _events.begin(); itr != _events.end(); ++itr) - if ((*itr)->GetCreatorGUID() == guid && ((*itr)->IsGuildEvent() || (*itr)->IsGuildAnnouncement())) + if ((*itr)->GetOwnerGUID() == guid && ((*itr)->IsGuildEvent() || (*itr)->IsGuildAnnouncement())) RemoveEvent((*itr)->GetEventId(), guid); CalendarInviteStore playerInvites = GetPlayerInvites(guid); @@ -370,22 +375,22 @@ void CalendarMgr::DeleteOldEvents() { CalendarEvent* event = *itr; ++itr; - if (event->GetEventTime() < oldEventsTime) + if (event->GetDate() < oldEventsTime) RemoveEvent(event, ObjectGuid::Empty); } } -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) - if ((*itr)->GetCreatorGUID() == guid && (includeGuildEvents || (!(*itr)->IsGuildEvent() && !(*itr)->IsGuildAnnouncement()))) + if ((*itr)->GetOwnerGUID() == guid && (includeGuildEvents || (!(*itr)->IsGuildEvent() && !(*itr)->IsGuildAnnouncement()))) result.insert(*itr); return result; } -CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) +CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) const { CalendarEventStore result; @@ -400,7 +405,7 @@ CalendarEventStore CalendarMgr::GetGuildEvents(ObjectGuid::LowType guildId) return result; } -CalendarEventStore CalendarMgr::GetPlayerEvents(ObjectGuid guid) +CalendarEventStore CalendarMgr::GetPlayerEvents(ObjectGuid guid) const { CalendarEventStore events; @@ -419,12 +424,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; @@ -460,254 +469,298 @@ uint32 CalendarMgr::GetPlayerNumPending(ObjectGuid guid) std::string CalendarEvent::BuildCalendarMailSubject(ObjectGuid remover) const { - std::ostringstream strm; - strm << remover.GetRawValue() << ':' << _title; - return strm.str(); + return Trinity::StringFormat("{}:{}", remover.GetRawValue(), _title); } -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(_eventTime); - 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()); - time_t statusTime = invite.GetStatusTime(); - bool hasStatusTime = statusTime != 946684800; // 01/01/2000 00:00:00 ObjectGuid invitee = invite.GetInviteeGUID(); Player* player = ObjectAccessor::FindConnectedPlayer(invitee); uint8 level = player ? player->GetLevel() : sCharacterCache->GetCharacterLevelByGuid(invitee); - WorldPacket data(SMSG_CALENDAR_EVENT_INVITE, 8 + 8 + 8 + 1 + 1 + 1 + (4) + 1); - data << invitee.WriteAsPacked(); - data << uint64(invite.GetEventId()); - data << uint64(invite.GetInviteId()); - data << uint8(level); - data << uint8(invite.GetStatus()); - data << uint8(hasStatusTime); - if (hasStatusTime) - data.AppendPackedTime(statusTime); - data << uint8(invite.GetSenderGUID() != invite.GetInviteeGUID()); // false only if the invite is sign-up + 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; + packet.ClearPending = invite.GetSenderGUID() != invite.GetInviteeGUID(); + + receiver->SendDirectMessage(packet.Write()); + }; if (!calendarEvent) // Pre-invite { if (Player* playerSender = ObjectAccessor::FindConnectedPlayer(invite.GetSenderGUID())) - playerSender->SendDirectMessage(&data); + packetBuilder(playerSender); } else { - if (calendarEvent->GetCreatorGUID() != invite.GetInviteeGUID()) // correct? - SendPacketToAllEventRelatives(data, *calendarEvent); + if (calendarEvent->GetOwnerGUID() != invite.GetInviteeGUID()) // correct? + for (Player* receiver : GetAllEventRelatives(*calendarEvent)) + packetBuilder(receiver); } } -void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t oldEventTime) +void CalendarMgr::SendCalendarEventUpdateAlert(CalendarEvent const& calendarEvent, time_t originalDate) const { - WorldPacket data(SMSG_CALENDAR_EVENT_UPDATED_ALERT, 1 + 8 + 4 + 4 + 4 + 1 + 4 + - calendarEvent.GetTitle().size() + calendarEvent.GetDescription().size() + 1 + 4 + 4); - data << uint8(1); // unk - data << uint64(calendarEvent.GetEventId()); - data.AppendPackedTime(oldEventTime); - data << uint32(calendarEvent.GetFlags()); - data.AppendPackedTime(calendarEvent.GetEventTime()); - data << uint8(calendarEvent.GetType()); - data << int32(calendarEvent.GetDungeonId()); - data << calendarEvent.GetTitle(); - data << calendarEvent.GetDescription(); - data << uint8(CALENDAR_REPEAT_NEVER); // repeatable - data << uint32(CALENDAR_MAX_INVITES); - data << uint32(0); // unk - - SendPacketToAllEventRelatives(data, calendarEvent); -} + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarEventUpdatedAlert packet; + packet.ClearPending = calendarEvent.GetOwnerGUID() == receiver->GetGUID(); + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.Description = calendarEvent.GetDescription(); + 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(); + + receiver->SendDirectMessage(packet.Write()); + }; + + for (Player* receiver : GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); +} + +void CalendarMgr::SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const +{ + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarInviteStatus packet; + packet.ClearPending = invite.GetInviteeGUID() == receiver->GetGUID(); + 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(); -void CalendarMgr::SendCalendarEventStatus(CalendarEvent const& calendarEvent, CalendarInvite const& invite) -{ - WorldPacket data(SMSG_CALENDAR_EVENT_STATUS, 8 + 8 + 4 + 4 + 1 + 1 + 4); - data << invite.GetInviteeGUID().WriteAsPacked(); - data << uint64(calendarEvent.GetEventId()); - data.AppendPackedTime(calendarEvent.GetEventTime()); - data << uint32(calendarEvent.GetFlags()); - data << uint8(invite.GetStatus()); - data << uint8(invite.GetRank()); - data.AppendPackedTime(invite.GetStatusTime()); + receiver->SendDirectMessage(packet.Write()); + }; - SendPacketToAllEventRelatives(data, calendarEvent); + for (Player* receiver : GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } -void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent) +void CalendarMgr::SendCalendarEventRemovedAlert(CalendarEvent const& calendarEvent) const { - WorldPacket data(SMSG_CALENDAR_EVENT_REMOVED_ALERT, 1 + 8 + 1); - data << uint8(1); // FIXME: If true does not SignalEvent(EVENT_CALENDAR_ACTION_PENDING) - data << uint64(calendarEvent.GetEventId()); - data.AppendPackedTime(calendarEvent.GetEventTime()); + auto packetBuilder = [&](Player const* receiver) + { + WorldPackets::Calendar::CalendarEventRemovedAlert packet; + packet.ClearPending = calendarEvent.GetOwnerGUID() == receiver->GetGUID(); + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += receiver->GetSession()->GetTimezoneOffset(); + packet.EventID = calendarEvent.GetEventId(); + + receiver->SendDirectMessage(packet.Write()); + }; - SendPacketToAllEventRelatives(data, calendarEvent); + 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 { - WorldPacket data(SMSG_CALENDAR_EVENT_INVITE_REMOVED, 8 + 4 + 4 + 1); - data << invite.GetInviteeGUID().WriteAsPacked(); - data << uint64(invite.GetEventId()); - data << uint32(flags); - data << uint8(1); // FIXME + WorldPackets::Calendar::CalendarInviteRemoved packet; + packet.ClearPending = true; // FIXME + packet.EventID = calendarEvent.GetEventId(); + packet.Flags = flags; + packet.InviteGuid = invite.GetInviteeGUID(); - SendPacketToAllEventRelatives(data, calendarEvent); + SendPacketToAllEventRelatives(packet.Write(), calendarEvent); } -void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventModeratorStatusAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const { - WorldPacket data(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, 8 + 8 + 1 + 1); - data << invite.GetInviteeGUID().WriteAsPacked(); - data << uint64(invite.GetEventId()); - data << uint8(invite.GetRank()); - data << uint8(1); // Unk boolean - Display to client? + WorldPackets::Calendar::CalendarModeratorStatus packet; + packet.ClearPending = true; // FIXME + packet.EventID = calendarEvent.GetEventId(); + packet.InviteGuid = invite.GetInviteeGUID(); + packet.Status = invite.GetStatus(); - SendPacketToAllEventRelatives(data, calendarEvent); + SendPacketToAllEventRelatives(packet.Write(), calendarEvent); } -void CalendarMgr::SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) +void CalendarMgr::SendCalendarEventInviteAlert(CalendarEvent const& calendarEvent, CalendarInvite const& invite) const { - WorldPacket data(SMSG_CALENDAR_EVENT_INVITE_ALERT); - data << uint64(calendarEvent.GetEventId()); - data << calendarEvent.GetTitle(); - data.AppendPackedTime(calendarEvent.GetEventTime()); - data << uint32(calendarEvent.GetFlags()); - data << uint32(calendarEvent.GetType()); - data << int32(calendarEvent.GetDungeonId()); - data << uint64(invite.GetInviteId()); - data << uint8(invite.GetStatus()); - data << uint8(invite.GetRank()); - data << calendarEvent.GetCreatorGUID().WriteAsPacked(); - data << invite.GetSenderGUID().WriteAsPacked(); + 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(); + + receiver->SendDirectMessage(packet.Write()); + }; if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) { if (Guild* guild = sGuildMgr->GetGuildById(calendarEvent.GetGuildId())) - guild->BroadcastPacket(&data); + guild->BroadcastWorker(packetBuilder); } - else - if (Player* player = ObjectAccessor::FindConnectedPlayer(invite.GetInviteeGUID())) - player->SendDirectMessage(&data); + else if (Player* player = ObjectAccessor::FindConnectedPlayer(invite.GetInviteeGUID())) + 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()]; - - WorldPacket data(SMSG_CALENDAR_SEND_EVENT, 60 + eventInviteeList.size() * 32); - data << uint8(sendType); - data << calendarEvent.GetCreatorGUID().WriteAsPacked(); - data << uint64(calendarEvent.GetEventId()); - data << calendarEvent.GetTitle(); - data << calendarEvent.GetDescription(); - data << uint8(calendarEvent.GetType()); - data << uint8(CALENDAR_REPEAT_NEVER); // repeatable - data << uint32(CALENDAR_MAX_INVITES); - data << int32(calendarEvent.GetDungeonId()); - data << uint32(calendarEvent.GetFlags()); - data.AppendPackedTime(calendarEvent.GetEventTime()); - data.AppendPackedTime(calendarEvent.GetTimeZoneTime()); - data << uint32(calendarEvent.GetGuildId()); - - data << uint32(eventInviteeList.size()); - for (CalendarInviteStore::const_iterator itr = eventInviteeList.begin(); itr != eventInviteeList.end(); ++itr) + WorldPackets::Calendar::CalendarSendEvent packet; + 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.SetUtcTimeFromUnixTime(calendarEvent.GetLockDate()); // Always 0 ? + if (calendarEvent.GetLockDate()) + packet.LockDate += player->GetSession()->GetTimezoneOffset(); + packet.OwnerGuid = calendarEvent.GetOwnerGUID(); + packet.TextureID = calendarEvent.GetTextureId(); + packet.EventGuildID = calendarEvent.GetGuildId(); + + if (CalendarInviteStore const* eventInviteeList = Trinity::Containers::MapGetValuePtr(_invites, calendarEvent.GetEventId())) { - CalendarInvite const* calendarInvite = (*itr); - 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); - - data << inviteeGuid.WriteAsPacked(); - data << uint8(inviteeLevel); - data << uint8(calendarInvite->GetStatus()); - data << uint8(calendarInvite->GetRank()); - data << uint8(calendarEvent.IsGuildEvent() && calendarEvent.GetGuildId() == inviteeGuildId); - data << uint64(calendarInvite->GetInviteId()); - data.AppendPackedTime(calendarInvite->GetStatusTime()); - data << calendarInvite->GetText(); + 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(&data); + 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)) { - WorldPacket data(SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT, 8 + 4 + 4 + 1); - data << uint64(calendarEvent.GetEventId()); - data.AppendPackedTime(calendarEvent.GetEventTime()); - data << uint32(calendarEvent.GetFlags()); - data << uint8(status); - - player->SendDirectMessage(&data); + WorldPackets::Calendar::CalendarInviteRemovedAlert packet; + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.GetDate()); + packet.Date += player->GetSession()->GetTimezoneOffset(); + packet.EventID = calendarEvent.GetEventId(); + packet.Flags = calendarEvent.GetFlags(); + packet.Status = status; + + player->SendDirectMessage(packet.Write()); } } -void CalendarMgr::SendCalendarClearPendingAction(ObjectGuid guid) +void CalendarMgr::SendCalendarClearPendingAction(ObjectGuid guid) const { if (Player* player = ObjectAccessor::FindConnectedPlayer(guid)) - { - WorldPacket data(SMSG_CALENDAR_CLEAR_PENDING_ACTION, 0); - player->SendDirectMessage(&data); - } + 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)) { - WorldPacket data(SMSG_CALENDAR_COMMAND_RESULT, 0); - data << uint32(0); - data << uint8(0); + WorldPackets::Calendar::CalendarCommandResult packet; + packet.Command = 1; // FIXME + packet.Result = err; + switch (err) { case CALENDAR_ERROR_OTHER_INVITES_EXCEEDED: case CALENDAR_ERROR_ALREADY_INVITED_TO_EVENT_S: case CALENDAR_ERROR_IGNORING_YOU_S: - data << param; + packet.Name = param; break; default: - data << uint8(0); break; } - data << uint32(err); - - player->SendDirectMessage(&data); + player->SendDirectMessage(packet.Write()); } } -void CalendarMgr::SendPacketToAllEventRelatives(WorldPacket& 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 056218217cb..22c5dbc6bf1 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 @@ -136,6 +137,8 @@ enum CalendarLimits CALENDAR_OLD_EVENTS_DELETION_TIME = 1 * MONTH, }; +#define CALENDAR_DEFAULT_RESPONSE_TIME 946684800 // 01/01/2000 00:00:00 + struct TC_GAME_API CalendarInvite { public: @@ -145,18 +148,24 @@ struct TC_GAME_API CalendarInvite _eventId = eventId; _invitee = calendarInvite.GetInviteeGUID(); _senderGUID = calendarInvite.GetSenderGUID(); - _statusTime = calendarInvite.GetStatusTime(); + _responseTime = calendarInvite.GetResponseTime(); _status = calendarInvite.GetStatus(); _rank = calendarInvite.GetRank(); - _text = calendarInvite.GetText(); + _note = calendarInvite.GetNote(); } CalendarInvite(); CalendarInvite(uint64 inviteId, uint64 eventId, ObjectGuid invitee, ObjectGuid senderGUID, time_t statusTime, - CalendarInviteStatus status, CalendarModerationRank rank, std::string text) : - _inviteId(inviteId), _eventId(eventId), _invitee(invitee), _senderGUID(senderGUID), _statusTime(statusTime), - _status(status), _rank(rank), _text(text) { } + CalendarInviteStatus status, CalendarModerationRank rank, std::string note) : + _inviteId(inviteId), _eventId(eventId), _invitee(invitee), _senderGUID(senderGUID), _responseTime(statusTime), + _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(); @@ -172,11 +181,11 @@ struct TC_GAME_API CalendarInvite void SetInvitee(ObjectGuid guid) { _invitee = guid; } ObjectGuid GetInviteeGUID() const { return _invitee; } - void SetStatusTime(time_t statusTime) { _statusTime = statusTime; } - time_t GetStatusTime() const { return _statusTime; } + void SetResponseTime(time_t statusTime) { _responseTime = statusTime; } + time_t GetResponseTime() const { return _responseTime; } - void SetText(const std::string& text) { _text = text; } - std::string GetText() const { return _text; } + void SetNote(std::string const& note) { _note = note; } + std::string GetNote() const { return _note; } void SetStatus(CalendarInviteStatus status) { _status = status; } CalendarInviteStatus GetStatus() const { return _status; } @@ -189,10 +198,10 @@ struct TC_GAME_API CalendarInvite uint64 _eventId; ObjectGuid _invitee; ObjectGuid _senderGUID; - time_t _statusTime; + time_t _responseTime; CalendarInviteStatus _status; CalendarModerationRank _rank; - std::string _text; + std::string _note; }; struct TC_GAME_API CalendarEvent @@ -201,78 +210,84 @@ struct TC_GAME_API CalendarEvent CalendarEvent(CalendarEvent const& calendarEvent, uint64 eventId) { _eventId = eventId; - _creatorGUID = calendarEvent.GetCreatorGUID(); - _guildId = calendarEvent.GetGuildId(); - _type = calendarEvent.GetType(); - _dungeonId = calendarEvent.GetDungeonId(); - _eventTime = calendarEvent.GetEventTime(); + _ownerGUID = calendarEvent.GetOwnerGUID(); + _eventGuildId = calendarEvent.GetGuildId(); + _eventType = calendarEvent.GetType(); + _textureId = calendarEvent.GetTextureId(); + _date = calendarEvent.GetDate(); _flags = calendarEvent.GetFlags(); - _timezoneTime = calendarEvent.GetTimeZoneTime(); _title = calendarEvent.GetTitle(); _description = calendarEvent.GetDescription(); + _lockDate = calendarEvent.GetLockDate(); } - CalendarEvent(uint64 eventId, ObjectGuid creatorGUID, ObjectGuid::LowType guildId, CalendarEventType type, int32 dungeonId, - time_t eventTime, uint32 flags, time_t timezoneTime, std::string title, std::string description) : - _eventId(eventId), _creatorGUID(creatorGUID), _guildId(guildId), _type(type), _dungeonId(dungeonId), - _eventTime(eventTime), _flags(flags), _timezoneTime(timezoneTime), _title(title), - _description(description) { } + 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(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) { } + + CalendarEvent(CalendarEvent const&) = delete; + CalendarEvent(CalendarEvent&&) = delete; - CalendarEvent() : _eventId(1), _creatorGUID(), _guildId(0), _type(CALENDAR_TYPE_OTHER), _dungeonId(-1), _eventTime(0), - _flags(0), _timezoneTime(0), _title(""), _description("") { } + CalendarEvent& operator=(CalendarEvent const&) = delete; + CalendarEvent& operator=(CalendarEvent&&) = delete; ~CalendarEvent(); void SetEventId(uint64 eventId) { _eventId = eventId; } uint64 GetEventId() const { return _eventId; } - void SetCreatorGUID(ObjectGuid guid) { _creatorGUID = guid; } - ObjectGuid GetCreatorGUID() const { return _creatorGUID; } + void SetOwnerGUID(ObjectGuid guid) { _ownerGUID = guid; } + ObjectGuid GetOwnerGUID() const { return _ownerGUID; } - void SetGuildId(ObjectGuid::LowType guildId) { _guildId = guildId; } - ObjectGuid::LowType GetGuildId() const { return _guildId; } + void SetGuildId(ObjectGuid::LowType guildId) { _eventGuildId = guildId; } + ObjectGuid::LowType GetGuildId() const { return _eventGuildId; } - void SetTitle(const std::string& title) { _title = title; } + void SetTitle(std::string const& title) { _title = title; } std::string GetTitle() const { return _title; } - void SetDescription(const std::string& description) { _description = description; } + void SetDescription(std::string const& description) { _description = description; } std::string GetDescription() const { return _description; } - void SetType(CalendarEventType type) { _type = type; } - CalendarEventType GetType() const { return _type; } + void SetType(CalendarEventType eventType) { _eventType = eventType; } + CalendarEventType GetType() const { return _eventType; } - void SetDungeonId(int32 dungeonId) { _dungeonId = dungeonId; } - int32 GetDungeonId() const { return _dungeonId; } + void SetTextureId(int32 textureId) { _textureId = textureId; } + int32 GetTextureId() const { return _textureId; } - void SetEventTime(time_t eventTime) { _eventTime = eventTime; } - time_t GetEventTime() const { return _eventTime; } + void SetDate(time_t date) { _date = date; } + time_t GetDate() const { return _date; } void SetFlags(uint32 flags) { _flags = flags; } uint32 GetFlags() const { return _flags; } - void SetTimeZoneTime(time_t timezoneTime) { _timezoneTime = timezoneTime; } - time_t GetTimeZoneTime() const { return _timezoneTime; } - bool IsGuildEvent() const { return (_flags & CALENDAR_FLAG_GUILD_EVENT) != 0; } bool IsGuildAnnouncement() const { return (_flags & CALENDAR_FLAG_WITHOUT_INVITES) != 0; } + bool IsLocked() const { return (_flags & CALENDAR_FLAG_INVITES_LOCKED) != 0; } + + void SetLockDate(time_t lockDate) { _lockDate = lockDate; } + time_t GetLockDate() const { return _lockDate; } static bool IsGuildEvent(uint32 flags) { return (flags & CALENDAR_FLAG_GUILD_EVENT) != 0; } 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; - ObjectGuid _creatorGUID; - ObjectGuid::LowType _guildId; - CalendarEventType _type; - int32 _dungeonId; - time_t _eventTime; + ObjectGuid _ownerGUID; + ObjectGuid::LowType _eventGuildId; + CalendarEventType _eventType; + int32 _textureId; + time_t _date; uint32 _flags; - time_t _timezoneTime; std::string _title; std::string _description; + time_t _lockDate; }; typedef std::vector<CalendarInvite*> CalendarInviteStore; typedef std::set<CalendarEvent*> CalendarEventStore; @@ -293,20 +308,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(); @@ -329,19 +350,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 oldEventTime); - 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& 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/Entities/Object/ObjectGuid.cpp b/src/server/game/Entities/Object/ObjectGuid.cpp index cf59885158b..ba0a75f2db2 100644 --- a/src/server/game/Entities/Object/ObjectGuid.cpp +++ b/src/server/game/Entities/Object/ObjectGuid.cpp @@ -85,6 +85,12 @@ ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid) return buf; } +ByteBuffer& operator<<(ByteBuffer& buf, PackedGuidWriter const& guid) +{ + buf.appendPackGUID(guid.Guid.GetRawValue()); + return buf; +} + ByteBuffer& operator>>(ByteBuffer& buf, PackedGuidReader const& guid) { buf.readPackGUID(reinterpret_cast<uint64&>(guid.Guid)); diff --git a/src/server/game/Entities/Object/ObjectGuid.h b/src/server/game/Entities/Object/ObjectGuid.h index 1a6ccb775b2..965040adee7 100644 --- a/src/server/game/Entities/Object/ObjectGuid.h +++ b/src/server/game/Entities/Object/ObjectGuid.h @@ -115,6 +115,12 @@ struct PackedGuidReader ObjectGuid& Guid; }; +struct PackedGuidWriter +{ + explicit PackedGuidWriter(ObjectGuid const& guid) : Guid(guid) { } + ObjectGuid const& Guid; +}; + class TC_GAME_API ObjectGuid { public: @@ -139,7 +145,7 @@ class TC_GAME_API ObjectGuid void Set(uint64 guid) { _guid = guid; } void Clear() { _guid = 0; } - PackedGuid WriteAsPacked() const; + PackedGuidWriter WriteAsPacked() const { return PackedGuidWriter(*this); } uint64 GetRawValue() const { return _guid; } HighGuid GetHigh() const { return HighGuid((_guid >> 48) & 0x0000FFFF); } @@ -293,10 +299,9 @@ TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, ObjectGuid const& guid); TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, ObjectGuid& guid); TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, PackedGuid const& guid); +TC_GAME_API ByteBuffer& operator<<(ByteBuffer& buf, PackedGuidWriter const& guid); TC_GAME_API ByteBuffer& operator>>(ByteBuffer& buf, PackedGuidReader const& guid); -inline PackedGuid ObjectGuid::WriteAsPacked() const { return PackedGuid(*this); } - namespace std { template<> diff --git a/src/server/game/Entities/Player/Player.cpp b/src/server/game/Entities/Player/Player.cpp index 5543652b36e..661a7ddb6c9 100644 --- a/src/server/game/Entities/Player/Player.cpp +++ b/src/server/game/Entities/Player/Player.cpp @@ -18887,7 +18887,7 @@ void Player::UnbindInstance(BoundInstancesMap::iterator &itr, Difficulty difficu } if (itr->second.perm) - GetSession()->SendCalendarRaidLockout(itr->second.save, false); + GetSession()->SendCalendarRaidLockoutRemoved(itr->second.save); itr->second.save->RemovePlayer(this); // save can become invalid m_boundInstances[difficulty].erase(itr++); @@ -18972,7 +18972,7 @@ void Player::BindToInstance() if (!IsGameMaster()) { BindToInstance(mapSave, true, EXTEND_STATE_KEEP); - GetSession()->SendCalendarRaidLockout(mapSave, true); + GetSession()->SendCalendarRaidLockoutAdded(mapSave); } } @@ -22728,7 +22728,7 @@ void Player::SendInitialPacketsBeforeAddToMap() static float const TimeSpeed = 0.01666667f; WorldPackets::Misc::LoginSetTimeSpeed loginSetTimeSpeed; loginSetTimeSpeed.NewSpeed = TimeSpeed; - loginSetTimeSpeed.GameTime = GameTime::GetGameTime(); + loginSetTimeSpeed.GameTime = *GameTime::GetWowTime(); loginSetTimeSpeed.GameTimeHolidayOffset = 0; /// @todo SendDirectMessage(loginSetTimeSpeed.Write()); diff --git a/src/server/game/Guilds/Guild.cpp b/src/server/game/Guilds/Guild.cpp index 672f5888ec1..568194d1f04 100644 --- a/src/server/game/Guilds/Guild.cpp +++ b/src/server/game/Guilds/Guild.cpp @@ -19,6 +19,7 @@ #include "AccountMgr.h" #include "Bag.h" #include "CalendarMgr.h" +#include "CalendarPackets.h" #include "CharacterCache.h" #include "Chat.h" #include "Config.h" @@ -1794,7 +1795,8 @@ void Guild::SendInfo(WorldSession* session) const { WorldPackets::Guild::GuildInfoResponse guildInfo; guildInfo.GuildName = m_name; - guildInfo.CreateDate = m_createdDate; + guildInfo.CreateDate.SetUtcTimeFromUnixTime(m_createdDate); + guildInfo.CreateDate += session->GetTimezoneOffset(); guildInfo.NumMembers = int32(m_members.size()); guildInfo.NumAccounts = m_accountsNumber; @@ -2163,34 +2165,32 @@ void Guild::BroadcastPacket(WorldPacket const* packet) const void Guild::MassInviteToEvent(WorldSession* session, uint32 minLevel, uint32 maxLevel, uint32 minRank) { - uint32 count = 0; - - WorldPacket data(SMSG_CALENDAR_FILTER_GUILD); - data << uint32(count); // count placeholder + WorldPackets::Calendar::CalendarEventInitialInvites packet(true); for (auto const& [guid, member] : m_members) { // not sure if needed, maybe client checks it as well - if (count >= CALENDAR_MAX_INVITES) + if (packet.Invites.size() >= CALENDAR_MAX_INVITES) { if (Player* player = session->GetPlayer()) sCalendarMgr->SendCalendarCommandResult(player->GetGUID(), CALENDAR_ERROR_INVITES_EXCEEDED); return; } + if (member.GetGUID() == session->GetPlayer()->GetGUID()) + continue; + uint32 level = sCharacterCache->GetCharacterLevelByGuid(member.GetGUID()); + if (level < minLevel || level > maxLevel) + continue; - if (member.GetGUID() != session->GetPlayer()->GetGUID() && level >= minLevel && level <= maxLevel && member.IsRankNotLower(minRank)) - { - data.appendPackGUID(member.GetGUID().GetRawValue()); - data << uint8(0); // unk - ++count; - } - } + if (!member.IsRankNotLower(minRank)) + continue; - data.put<uint32>(0, count); + packet.Invites.emplace_back(member.GetGUID(), level); + } - session->SendPacket(&data); + session->SendPacket(packet.Write()); } // Members handling diff --git a/src/server/game/Handlers/CalendarHandler.cpp b/src/server/game/Handlers/CalendarHandler.cpp index 7044f8c0fb5..11d9f9ac99e 100644 --- a/src/server/game/Handlers/CalendarHandler.cpp +++ b/src/server/game/Handlers/CalendarHandler.cpp @@ -37,6 +37,7 @@ Copied events should probably have a new owner #include "WorldSession.h" #include "ArenaTeamMgr.h" #include "CalendarMgr.h" +#include "CalendarPackets.h" #include "CharacterCache.h" #include "DatabaseEnv.h" #include "DBCStores.h" @@ -53,56 +54,45 @@ Copied events should probably have a new owner #include "SocialMgr.h" #include "World.h" -void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) +void WorldSession::HandleCalendarGetCalendar(WorldPackets::Calendar::CalendarGetCalendar& /*calendarGetCalendar*/) { ObjectGuid guid = _player->GetGUID(); TC_LOG_DEBUG("network", "CMSG_CALENDAR_GET_CALENDAR [{}]", guid.ToString()); time_t currTime = GameTime::GetGameTime(); - WorldPacket data(SMSG_CALENDAR_SEND_CALENDAR, 1000); // Average size if no instance + WorldPackets::Calendar::CalendarSendCalendar packet; + packet.ServerTime = *GameTime::GetWowTime(); + packet.ServerNow = currTime; + packet.RaidOrigin = 1135753200; // Constant date, unk (28.12.2005 07:00) - CalendarInviteStore invites = sCalendarMgr->GetPlayerInvites(guid); - data << uint32(invites.size()); - for (CalendarInviteStore::const_iterator itr = invites.begin(); itr != invites.end(); ++itr) + CalendarInviteStore playerInvites = sCalendarMgr->GetPlayerInvites(guid); + for (CalendarInvite const* invite : playerInvites) { - data << uint64((*itr)->GetEventId()); - data << uint64((*itr)->GetInviteId()); - data << uint8((*itr)->GetStatus()); - data << uint8((*itr)->GetRank()); - - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent((*itr)->GetEventId())) - { - data << uint8(calendarEvent->IsGuildEvent()); - data << calendarEvent->GetCreatorGUID().WriteAsPacked(); - } - else - { - data << uint8(0); - data << (*itr)->GetSenderGUID().WriteAsPacked(); - } + WorldPackets::Calendar::CalendarSendCalendarInviteInfo& inviteInfo = packet.Invites.emplace_back(); + inviteInfo.EventID = invite->GetEventId(); + inviteInfo.InviteID = invite->GetInviteId(); + inviteInfo.InviterGuid = invite->GetSenderGUID(); + inviteInfo.Status = invite->GetStatus(); + inviteInfo.Moderator = invite->GetRank(); + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(invite->GetEventId())) + inviteInfo.InviteType = calendarEvent->IsGuildEvent() && calendarEvent->GetGuildId() == _player->GetGuildId(); } CalendarEventStore playerEvents = sCalendarMgr->GetPlayerEvents(guid); - data << uint32(playerEvents.size()); - for (CalendarEventStore::const_iterator itr = playerEvents.begin(); itr != playerEvents.end(); ++itr) + for (CalendarEvent const* event : playerEvents) { - CalendarEvent* calendarEvent = *itr; - - data << uint64(calendarEvent->GetEventId()); - data << calendarEvent->GetTitle(); - data << uint32(calendarEvent->GetType()); - data.AppendPackedTime(calendarEvent->GetEventTime()); - data << uint32(calendarEvent->GetFlags()); - data << int32(calendarEvent->GetDungeonId()); - data << calendarEvent->GetCreatorGUID().WriteAsPacked(); + WorldPackets::Calendar::CalendarSendCalendarEventInfo& eventInfo = packet.Events.emplace_back(); + eventInfo.EventID = event->GetEventId(); + eventInfo.Date.SetUtcTimeFromUnixTime(event->GetDate()); + eventInfo.Date += GetTimezoneOffset(); + eventInfo.EventName = event->GetTitle(); + eventInfo.EventType = event->GetType(); + eventInfo.Flags = event->GetFlags(); + eventInfo.OwnerGuid = event->GetOwnerGUID(); + eventInfo.TextureID = event->GetTextureId(); } - data << uint32(currTime); // server time - data.AppendPackedTime(currTime); // zone time - - ByteBuffer dataBuffer; - uint32 boundCounter = 0; for (uint8 i = 0; i < MAX_DIFFICULTY; ++i) { Player::BoundInstancesMap boundInstances = _player->GetBoundInstances(Difficulty(i)); @@ -111,24 +101,16 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) if (itr->second.perm) { InstanceSave const* save = itr->second.save; - dataBuffer << uint32(save->GetMapId()); - dataBuffer << uint32(save->GetDifficulty()); - dataBuffer << uint32(save->GetResetTime() - currTime); - dataBuffer << uint64(save->GetInstanceId()); // instance save id as unique instance copy id - ++boundCounter; + WorldPackets::Calendar::CalendarSendCalendarRaidLockoutInfo& lockoutInfo = packet.RaidLockouts.emplace_back(); + lockoutInfo.MapID = save->GetMapId(); + lockoutInfo.DifficultyID = save->GetDifficulty(); + lockoutInfo.ExpireTime = int32(std::max(save->GetResetTime() - currTime, SI64LIT(0))); + lockoutInfo.InstanceID = save->GetInstanceId(); } } } - data << uint32(boundCounter); - data.append(dataBuffer); - - data << uint32(1135753200); // Constant date, unk (28.12.2005 07:00) - - // Reuse variables - boundCounter = 0; std::set<uint32> sentMaps; - dataBuffer.clear(); ResetTimeByMapDifficultyMap const& resets = sInstanceSaveMgr->GetResetTimeMap(); for (ResetTimeByMapDifficultyMap::const_iterator itr = resets.begin(); itr != resets.end(); ++itr) @@ -143,128 +125,94 @@ void WorldSession::HandleCalendarGetCalendar(WorldPacket& /*recvData*/) sentMaps.insert(mapId); - dataBuffer << int32(mapId); - dataBuffer << int32(itr->second - currTime); - dataBuffer << int32(0); // Never seen anything else in sniffs - still unknown - ++boundCounter; + WorldPackets::Calendar::CalendarSendCalendarRaidResetInfo& reset = packet.RaidResets.emplace_back(); + reset.MapID = mapId; + reset.Duration = itr->second - currTime; + reset.Offset = 0; // Never seen anything else in sniffs - still unknown } - data << uint32(boundCounter); - data.append(dataBuffer); - - data << uint32(sGameEventMgr->modifiedHolidays.size()); for (uint32 entry : sGameEventMgr->modifiedHolidays) { HolidaysEntry const* holiday = sHolidaysStore.LookupEntry(entry); - data << uint32(holiday->ID); // m_ID - data << uint32(holiday->Region); // m_region, might be looping - data << uint32(holiday->Looping); // m_looping, might be region - data << uint32(holiday->Priority); // m_priority - data << uint32(holiday->CalendarFilterType); // m_calendarFilterType + WorldPackets::Calendar::CalendarSendCalendarHolidayInfo& holidayInfo = packet.Holidays.emplace_back(); + holidayInfo.HolidayID = holiday->ID; + holidayInfo.Region = holiday->Region; + holidayInfo.Looping = holiday->Looping; + holidayInfo.Priority = holiday->Priority; + holidayInfo.FilterType = holiday->CalendarFilterType; for (uint8 j = 0; j < MAX_HOLIDAY_DATES; ++j) - data << uint32(holiday->Date[j]); // 26 * m_date -- WritePackedTime ? + holidayInfo.Date[j].SetPackedTime(holiday->Date[j]); for (uint8 j = 0; j < MAX_HOLIDAY_DURATIONS; ++j) - data << uint32(holiday->Duration[j]); // 10 * m_duration + holidayInfo.Duration[j] = holiday->Duration[j]; for (uint8 j = 0; j < MAX_HOLIDAY_FLAGS; ++j) - data << uint32(holiday->CalendarFlags[j]); // 10 * m_calendarFlags + holidayInfo.CalendarFlags[j] = holiday->CalendarFlags[j]; - data << holiday->TextureFilename; // m_textureFilename (holiday name) + holidayInfo.TextureFilename = holiday->TextureFilename; } - SendPacket(&data); + SendPacket(packet.Write()); } -void WorldSession::HandleCalendarGetEvent(WorldPacket& recvData) +void WorldSession::HandleCalendarGetEvent(WorldPackets::Calendar::CalendarGetEvent& calendarGetEvent) { - uint64 eventId; - recvData >> eventId; - - TC_LOG_DEBUG("network", "CMSG_CALENDAR_GET_EVENT. Player [{}] Event [{}]", _player->GetGUID().ToString(), eventId); + TC_LOG_DEBUG("network", "CMSG_CALENDAR_GET_EVENT. Player [{}] Event [{}]", _player->GetGUID().ToString(), calendarGetEvent.EventID); - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarGetEvent.EventID)) sCalendarMgr->SendCalendarEvent(_player->GetGUID(), *calendarEvent, CALENDAR_SENDTYPE_GET); else sCalendarMgr->SendCalendarCommandResult(_player->GetGUID(), CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarGuildFilter(WorldPacket& recvData) +void WorldSession::HandleCalendarGuildFilter(WorldPackets::Calendar::CalendarGuildFilter& calendarGuildFilter) { - TC_LOG_DEBUG("network", "CMSG_CALENDAR_GUILD_FILTER [{}]", _player->GetGUID().ToString()); - - uint32 minLevel; - uint32 maxLevel; - uint32 minRank; - - recvData >> minLevel >> maxLevel >> minRank; - if (Guild* guild = sGuildMgr->GetGuildById(_player->GetGuildId())) - guild->MassInviteToEvent(this, minLevel, maxLevel, minRank); + guild->MassInviteToEvent(this, calendarGuildFilter.MinLevel, calendarGuildFilter.MaxLevel, calendarGuildFilter.MaxRankOrder); - TC_LOG_DEBUG("network", "CMSG_CALENDAR_GUILD_FILTER: Min level [{}], Max level [{}], Min rank [{}]", minLevel, maxLevel, minRank); + TC_LOG_DEBUG("network", "CMSG_CALENDAR_GUILD_FILTER: Min level [{}], Max level [{}], Min rank [{}]", + calendarGuildFilter.MinLevel, calendarGuildFilter.MaxLevel, calendarGuildFilter.MaxRankOrder); } -void WorldSession::HandleCalendarArenaTeam(WorldPacket& recvData) +void WorldSession::HandleCalendarArenaTeam(WorldPackets::Calendar::CalendarArenaTeam& calendarArenaTeam) { TC_LOG_DEBUG("network", "CMSG_CALENDAR_ARENA_TEAM [{}]", _player->GetGUID().ToString()); - uint32 arenaTeamId; - recvData >> arenaTeamId; - - if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(arenaTeamId)) + if (ArenaTeam* team = sArenaTeamMgr->GetArenaTeamById(calendarArenaTeam.ArenaTeamId)) team->MassInviteToEvent(this); } -void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) +void WorldSession::HandleCalendarAddEvent(WorldPackets::Calendar::CalendarAddEvent& calendarAddEvent) { ObjectGuid guid = _player->GetGUID(); - std::string title; - std::string description; - uint8 type; - uint8 repeatable; - uint32 maxInvites; - int32 dungeonId; - uint32 eventPackedTime; - uint32 unkPackedTime; - uint32 flags; - - recvData >> title >> description >> type >> repeatable >> maxInvites >> dungeonId; - recvData.ReadPackedTime(eventPackedTime); - recvData.ReadPackedTime(unkPackedTime); - recvData >> flags; - - eventPackedTime = uint32(LocalTimeToUTCTime(eventPackedTime)); + calendarAddEvent.Time -= GetTimezoneOffset(); + calendarAddEvent.LockDate -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (time_t(eventPackedTime) < (GameTime::GetGameTime() - time_t(86400L))) + if (calendarAddEvent.Time < *GameTime::GetUtcWowTime()) { - recvData.rfinish(); sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_PASSED); return; } // If the event is a guild event, check if the player is in a guild - if (CalendarEvent::IsGuildEvent(flags) || CalendarEvent::IsGuildAnnouncement(flags)) + if (CalendarEvent::IsGuildEvent(calendarAddEvent.Flags) || CalendarEvent::IsGuildAnnouncement(calendarAddEvent.Flags)) { if (!_player->GetGuildId()) { - recvData.rfinish(); sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_GUILD_PLAYER_NOT_IN_GUILD); return; } } // Check if the player reached the max number of events allowed to create - if (CalendarEvent::IsGuildEvent(flags) || CalendarEvent::IsGuildAnnouncement(flags)) + if (CalendarEvent::IsGuildEvent(calendarAddEvent.Flags) || CalendarEvent::IsGuildAnnouncement(calendarAddEvent.Flags)) { if (sCalendarMgr->GetGuildEvents(_player->GetGuildId()).size() >= CALENDAR_MAX_GUILD_EVENTS) { - recvData.rfinish(); sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_GUILD_EVENTS_EXCEEDED); return; } @@ -273,7 +221,6 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) { if (sCalendarMgr->GetEventsCreatedBy(guid).size() >= CALENDAR_MAX_EVENTS) { - recvData.rfinish(); sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENTS_EXCEEDED); return; } @@ -281,165 +228,102 @@ void WorldSession::HandleCalendarAddEvent(WorldPacket& recvData) if (GetCalendarEventCreationCooldown() > GameTime::GetGameTime()) { - recvData.rfinish(); sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_INTERNAL); return; } SetCalendarEventCreationCooldown(GameTime::GetGameTime() + CALENDAR_CREATE_EVENT_COOLDOWN); - CalendarEvent* calendarEvent = new CalendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(type), dungeonId, - time_t(eventPackedTime), flags, time_t(unkPackedTime), title, description); + CalendarEvent* calendarEvent = new CalendarEvent(sCalendarMgr->GetFreeEventId(), guid, 0, CalendarEventType(calendarAddEvent.EventType), calendarAddEvent.TextureID, + calendarAddEvent.Time.GetUnixTimeFromUtcTime(), calendarAddEvent.Flags, calendarAddEvent.Title, calendarAddEvent.Description, calendarAddEvent.LockDate.GetUnixTimeFromUtcTime()); if (calendarEvent->IsGuildEvent() || calendarEvent->IsGuildAnnouncement()) calendarEvent->SetGuildId(_player->GetGuildId()); if (calendarEvent->IsGuildAnnouncement()) { - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite invite(0, calendarEvent->GetEventId(), ObjectGuid::Empty, guid, 946684800, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); + CalendarInvite invite(0, calendarEvent->GetEventId(), ObjectGuid::Empty, guid, CALENDAR_DEFAULT_RESPONSE_TIME, CALENDAR_STATUS_NOT_SIGNED_UP, CALENDAR_RANK_PLAYER, ""); // WARNING: By passing pointer to a local variable, the underlying method(s) must NOT perform any kind // of storage of the pointer as it will lead to memory corruption sCalendarMgr->AddInvite(calendarEvent, &invite); } else { - // client limits the amount of players to be invited to 100 - - uint32 inviteCount; - ObjectGuid invitee[CALENDAR_MAX_INVITES]; - uint8 status[CALENDAR_MAX_INVITES]; - uint8 rank[CALENDAR_MAX_INVITES]; - - memset(status, 0, sizeof(status)); - memset(rank, 0, sizeof(rank)); - - try - { - recvData >> inviteCount; - - for (uint32 i = 0; i < inviteCount && i < CALENDAR_MAX_INVITES; ++i) - { - recvData >> invitee[i].ReadAsPacked(); - recvData >> status[i] >> rank[i]; - } - } - catch (ByteBufferException const&) - { - delete calendarEvent; - calendarEvent = nullptr; - throw; - } - CharacterDatabaseTransaction trans; - if (inviteCount > 1) + if (calendarAddEvent.Invites.size() > 1) trans = CharacterDatabase.BeginTransaction(); - for (uint32 i = 0; i < inviteCount && i < CALENDAR_MAX_INVITES; ++i) + for (uint32 i = 0; i < calendarAddEvent.Invites.size(); ++i) { - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), invitee[i], guid, 946684800, CalendarInviteStatus(status[i]), CalendarModerationRank(rank[i]), ""); + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEvent->GetEventId(), calendarAddEvent.Invites[i].Guid, + guid, CALENDAR_DEFAULT_RESPONSE_TIME, CalendarInviteStatus(calendarAddEvent.Invites[i].Status), + CalendarModerationRank(calendarAddEvent.Invites[i].Moderator), ""); sCalendarMgr->AddInvite(calendarEvent, invite, trans); } - if (inviteCount > 1) + if (calendarAddEvent.Invites.size() > 1) CharacterDatabase.CommitTransaction(trans); } sCalendarMgr->AddEvent(calendarEvent, CALENDAR_SENDTYPE_ADD); } -void WorldSession::HandleCalendarUpdateEvent(WorldPacket& recvData) +void WorldSession::HandleCalendarUpdateEvent(WorldPackets::Calendar::CalendarUpdateEvent& calendarUpdateEvent) { - ObjectGuid guid = _player->GetGUID(); - time_t oldEventTime; - - uint64 eventId; - uint64 inviteId; - std::string title; - std::string description; - uint8 type; - uint8 repetitionType; - uint32 maxInvites; - int32 dungeonId; - uint32 eventPackedTime; - uint32 timeZoneTime; - uint32 flags; - - recvData >> eventId >> inviteId >> title >> description >> type >> repetitionType >> maxInvites >> dungeonId; - recvData.ReadPackedTime(eventPackedTime); - recvData.ReadPackedTime(timeZoneTime); - recvData >> flags; - - eventPackedTime = uint32(LocalTimeToUTCTime(eventPackedTime)); + calendarUpdateEvent.Time -= GetTimezoneOffset(); + calendarUpdateEvent.LockDate -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (time_t(eventPackedTime) < (GameTime::GetGameTime() - time_t(86400L))) - { - recvData.rfinish(); + if (calendarUpdateEvent.Time < *GameTime::GetUtcWowTime()) return; - } TC_LOG_DEBUG("network", "CMSG_CALENDAR_UPDATE_EVENT [{}] EventId [{}], " - "InviteId [{}] Title {}, Description {}, type {} " - "Repeatable {}, MaxInvites {}, Dungeon ID {}, Time {} " - "Time2 {}, Flags {}", guid.ToString(), eventId, inviteId, title, - description, type, repetitionType, maxInvites, dungeonId, - eventPackedTime, timeZoneTime, flags); + "InviteId [{}] Title {}, Description {}, EventType {} " + "Dungeon ID {}, Time {} LockDate {}, Flags {}", _player->GetGUID().ToString(), calendarUpdateEvent.EventID, calendarUpdateEvent.ModeratorID, + calendarUpdateEvent.Title, calendarUpdateEvent.Description, calendarUpdateEvent.EventType, calendarUpdateEvent.TextureID, + calendarUpdateEvent.Time.GetUnixTimeFromUtcTime(), calendarUpdateEvent.LockDate.GetUnixTimeFromUtcTime(), calendarUpdateEvent.Flags); - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarUpdateEvent.EventID)) { - oldEventTime = calendarEvent->GetEventTime(); + time_t oldEventTime = calendarEvent->GetDate(); - calendarEvent->SetType(CalendarEventType(type)); - calendarEvent->SetFlags(flags); - calendarEvent->SetEventTime(time_t(eventPackedTime)); - calendarEvent->SetTimeZoneTime(time_t(timeZoneTime)); // Not sure, seems constant from the little sniffs we have - calendarEvent->SetDungeonId(dungeonId); - calendarEvent->SetTitle(title); - calendarEvent->SetDescription(description); + calendarEvent->SetType(CalendarEventType(calendarUpdateEvent.EventType)); + calendarEvent->SetFlags(calendarUpdateEvent.Flags); + calendarEvent->SetDate(calendarUpdateEvent.Time.GetUnixTimeFromUtcTime()); + calendarEvent->SetLockDate(calendarUpdateEvent.LockDate.GetUnixTimeFromUtcTime()); // Not sure, seems constant from the little sniffs we have + calendarEvent->SetTextureId(calendarUpdateEvent.TextureID); + calendarEvent->SetTitle(calendarUpdateEvent.Title); + calendarEvent->SetDescription(calendarUpdateEvent.Description); sCalendarMgr->UpdateEvent(calendarEvent); sCalendarMgr->SendCalendarEventUpdateAlert(*calendarEvent, oldEventTime); } else - sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); + sCalendarMgr->SendCalendarCommandResult(_player->GetGUID(), CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarRemoveEvent(WorldPacket& recvData) +void WorldSession::HandleCalendarRemoveEvent(WorldPackets::Calendar::CalendarRemoveEvent& calendarRemoveEvent) { ObjectGuid guid = _player->GetGUID(); - uint64 eventId; - - recvData >> eventId; - recvData.rfinish(); // Skip flags & invite ID, we don't use them - - sCalendarMgr->RemoveEvent(eventId, guid); + sCalendarMgr->RemoveEvent(calendarRemoveEvent.EventID, guid); } -void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) +void WorldSession::HandleCalendarCopyEvent(WorldPackets::Calendar::CalendarCopyEvent& calendarCopyEvent) { ObjectGuid guid = _player->GetGUID(); - uint64 eventId; - uint64 inviteId; - uint32 eventTime; - - recvData >> eventId >> inviteId; - recvData.ReadPackedTime(eventTime); - TC_LOG_DEBUG("network", "CMSG_CALENDAR_COPY_EVENT [{}], EventId [{}] inviteId [{}] Time: {}", - guid.ToString(), eventId, inviteId, eventTime); - eventTime = uint32(LocalTimeToUTCTime(eventTime)); + calendarCopyEvent.Date -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (time_t(eventTime) < (GameTime::GetGameTime() - time_t(86400L))) + if (calendarCopyEvent.Date < *GameTime::GetUtcWowTime()) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_PASSED); return; } - if (CalendarEvent* oldEvent = sCalendarMgr->GetEvent(eventId)) + TC_LOG_DEBUG("network", "CMSG_CALENDAR_COPY_EVENT [{}], EventId [{}] inviteId [{}] Time: {}", + guid.ToString(), calendarCopyEvent.EventID, calendarCopyEvent.ModeratorID, calendarCopyEvent.Date.GetUnixTimeFromUtcTime()); + + if (CalendarEvent* oldEvent = sCalendarMgr->GetEvent(calendarCopyEvent.EventID)) { // Ensure that the player has access to the event if (oldEvent->IsGuildEvent() || oldEvent->IsGuildAnnouncement()) @@ -452,7 +336,7 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) } else { - if (oldEvent->GetCreatorGUID() != guid) + if (oldEvent->GetOwnerGUID() != guid) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); return; @@ -485,10 +369,10 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) SetCalendarEventCreationCooldown(GameTime::GetGameTime() + CALENDAR_CREATE_EVENT_COOLDOWN); CalendarEvent* newEvent = new CalendarEvent(*oldEvent, sCalendarMgr->GetFreeEventId()); - newEvent->SetEventTime(time_t(eventTime)); + newEvent->SetDate(calendarCopyEvent.Date.GetUnixTimeFromUtcTime()); sCalendarMgr->AddEvent(newEvent, CALENDAR_SENDTYPE_COPY); - CalendarInviteStore invites = sCalendarMgr->GetEventInvites(eventId); + CalendarInviteStore invites = sCalendarMgr->GetEventInvites(calendarCopyEvent.EventID); CharacterDatabaseTransaction trans; if (invites.size() > 1) trans = CharacterDatabase.BeginTransaction(); @@ -504,113 +388,100 @@ void WorldSession::HandleCalendarCopyEvent(WorldPacket& recvData) sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarEventInvite(WorldPacket& recvData) +void WorldSession::HandleCalendarEventInvite(WorldPackets::Calendar::CalendarInvite& calendarEventInvite) { - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_INVITE"); - ObjectGuid playerGuid = _player->GetGUID(); - uint64 eventId; - uint64 inviteId; - std::string name; - bool isPreInvite; - bool isGuildEvent; + Optional<uint64> eventId; + if (!calendarEventInvite.Creating) + eventId = calendarEventInvite.EventID; - ObjectGuid inviteeGuid; - uint32 inviteeTeam = 0; - uint32 inviteeGuildId = 0; + bool isSignUp = calendarEventInvite.IsSignUp; - recvData >> eventId >> inviteId >> name >> isPreInvite >> isGuildEvent; + std::string inviteeName = calendarEventInvite.Name; - if (!normalizePlayerName(name)) + if (!normalizePlayerName(calendarEventInvite.Name)) return; - if (Player* player = ObjectAccessor::FindConnectedPlayerByName(name)) - { - // Invitee is online - inviteeGuid = player->GetGUID(); - inviteeTeam = player->GetTeam(); - inviteeGuildId = player->GetGuildId(); - } - else + auto createInvite = [this, playerGuid, inviteeName, eventId, isSignUp](ObjectGuid const& inviteeGuid, uint32 inviteeTeam, ObjectGuid::LowType inviteeGuildId, bool inviteeIsIngoring) { - // Invitee offline, get data from storage - ObjectGuid guid = sCharacterCache->GetCharacterGuidByName(name); - if (!guid.IsEmpty()) + if (!_player || _player->GetGUID() != playerGuid) + return; + + if (_player->GetTeam() != inviteeTeam && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR)) { - if (CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByGuid(guid)) - { - inviteeGuid = guid; - inviteeTeam = Player::TeamForRace(characterInfo->Race); - inviteeGuildId = characterInfo->GuildId; - } + sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NOT_ALLIED); + return; } - } - - if (!inviteeGuid) - { - sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_PLAYER_NOT_FOUND); - return; - } - if (_player->GetTeam() != inviteeTeam && !sWorld->getBoolConfig(CONFIG_ALLOW_TWO_SIDE_INTERACTION_CALENDAR)) - { - sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NOT_ALLIED); - return; - } - - if (QueryResult result = CharacterDatabase.PQuery("SELECT flags FROM character_social WHERE guid = {} AND friend = {}", inviteeGuid.GetCounter(), playerGuid.GetCounter())) - { - Field* fields = result->Fetch(); - if (fields[0].GetUInt8() & SOCIAL_FLAG_IGNORED) + if (inviteeIsIngoring) { - sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_IGNORING_YOU_S, name.c_str()); + sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_IGNORING_YOU_S, inviteeName.c_str()); return; } - } - if (!isPreInvite) - { - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (eventId) + { + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(*eventId)) + { + if (calendarEvent->IsGuildEvent() && calendarEvent->GetGuildId() == inviteeGuildId) + { + // we can't invite guild members to guild events + sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NO_GUILD_INVITES); + return; + } + + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), *eventId, inviteeGuid, playerGuid, CALENDAR_DEFAULT_RESPONSE_TIME, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); + sCalendarMgr->AddInvite(calendarEvent, invite); + } + else + sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_EVENT_INVALID); + } + else { - if (calendarEvent->IsGuildEvent() && calendarEvent->GetGuildId() == inviteeGuildId) + if (isSignUp && inviteeGuildId == _player->GetGuildId()) { - // we can't invite guild members to guild events sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NO_GUILD_INVITES); return; } - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), eventId, inviteeGuid, playerGuid, 946684800, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); - sCalendarMgr->AddInvite(calendarEvent, invite); + CalendarInvite invite(sCalendarMgr->GetFreeInviteId(), 0L, inviteeGuid, playerGuid, CALENDAR_DEFAULT_RESPONSE_TIME, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); + sCalendarMgr->SendCalendarEventInvite(invite); } - else - sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_EVENT_INVALID); + }; + + if (Player* player = ObjectAccessor::FindConnectedPlayerByName(calendarEventInvite.Name)) + { + // Invitee is online + createInvite(player->GetGUID(), player->GetTeam(), player->GetGuildId(), player->GetSocial()->HasIgnore(playerGuid)); } else { - if (isGuildEvent && inviteeGuildId == _player->GetGuildId()) + // Invitee offline, get data from storage + CharacterCacheEntry const* characterInfo = sCharacterCache->GetCharacterCacheByName(inviteeName); + if (!characterInfo) { - sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_NO_GUILD_INVITES); + sCalendarMgr->SendCalendarCommandResult(playerGuid, CALENDAR_ERROR_PLAYER_NOT_FOUND); return; } - // 946684800 is 01/01/2000 00:00:00 - default response time - CalendarInvite invite(inviteId, 0, inviteeGuid, playerGuid, 946684800, CALENDAR_STATUS_INVITED, CALENDAR_RANK_PLAYER, ""); - sCalendarMgr->SendCalendarEventInvite(invite); + GetQueryProcessor().AddCallback(CharacterDatabase.AsyncQuery(Trinity::StringFormat("SELECT 1 FROM character_social WHERE guid = {} AND friend = {} AND (cs.flags & {}) <> 0", + characterInfo->Guid.GetCounter(), playerGuid.GetCounter(), SOCIAL_FLAG_IGNORED).c_str())) + .WithCallback([inviteeGuid = characterInfo->Guid, inviteeTeam = Player::TeamForRace(characterInfo->Race), inviteeGuildId = characterInfo->GuildId, continuation = std::move(createInvite)](QueryResult result) + { + bool isIgnoring = result != nullptr; + continuation(inviteeGuid, inviteeTeam, inviteeGuildId, isIgnoring); + }); } } -void WorldSession::HandleCalendarEventSignup(WorldPacket& recvData) +void WorldSession::HandleCalendarEventSignup(WorldPackets::Calendar::CalendarEventSignUp& calendarEventSignUp) { ObjectGuid guid = _player->GetGUID(); - uint64 eventId; - bool tentative; - recvData >> eventId >> tentative; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_SIGNUP [{}] EventId [{}] Tentative {}", guid.ToString(), eventId, tentative); + TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_SIGNUP [{}] EventId [{}] Tentative {}", guid.ToString(), calendarEventSignUp.EventID, calendarEventSignUp.Tentative); - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarEventSignUp.EventID)) { if (calendarEvent->IsGuildEvent() && calendarEvent->GetGuildId() != _player->GetGuildId()) { @@ -618,8 +489,8 @@ void WorldSession::HandleCalendarEventSignup(WorldPacket& recvData) return; } - CalendarInviteStatus status = tentative ? CALENDAR_STATUS_TENTATIVE : CALENDAR_STATUS_SIGNED_UP; - CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), eventId, guid, guid, GameTime::GetGameTime(), status, CALENDAR_RANK_PLAYER, ""); + CalendarInviteStatus status = calendarEventSignUp.Tentative ? CALENDAR_STATUS_TENTATIVE : CALENDAR_STATUS_SIGNED_UP; + CalendarInvite* invite = new CalendarInvite(sCalendarMgr->GetFreeInviteId(), calendarEventSignUp.EventID, guid, guid, GameTime::GetGameTime(), status, CALENDAR_RANK_PLAYER, ""); sCalendarMgr->AddInvite(calendarEvent, invite); sCalendarMgr->SendCalendarClearPendingAction(guid); } @@ -627,30 +498,23 @@ void WorldSession::HandleCalendarEventSignup(WorldPacket& recvData) sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarEventRsvp(WorldPacket& recvData) +void WorldSession::HandleCalendarEventRsvp(WorldPackets::Calendar::CalendarRSVP& calendarRSVP) { ObjectGuid guid = _player->GetGUID(); - uint64 eventId; - uint64 inviteId; - uint32 status; - - recvData >> eventId >> inviteId >> status; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_RSVP [{}] EventId [{}], InviteId [{}], status {}", - guid.ToString(), eventId, inviteId, status); - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarRSVP.EventID)) { - // i think we still should be able to remove self from locked events - if (status != CALENDAR_STATUS_REMOVED && calendarEvent->GetFlags() & CALENDAR_FLAG_INVITES_LOCKED) + // I think we still should be able to remove self from locked events + if (calendarRSVP.Status != CALENDAR_STATUS_REMOVED && calendarEvent->IsLocked()) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_LOCKED); return; } - if (CalendarInvite* invite = sCalendarMgr->GetInvite(inviteId)) + if (CalendarInvite* invite = sCalendarMgr->GetInvite(calendarRSVP.InviteID)) { - invite->SetStatus(CalendarInviteStatus(status)); - invite->SetStatusTime(GameTime::GetGameTime()); + invite->SetStatus(CalendarInviteStatus(calendarRSVP.Status)); + invite->SetResponseTime(GameTime::GetGameTime()); sCalendarMgr->UpdateInvite(invite); sCalendarMgr->SendCalendarEventStatus(*calendarEvent, *invite); @@ -663,59 +527,43 @@ void WorldSession::HandleCalendarEventRsvp(WorldPacket& recvData) sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarEventRemoveInvite(WorldPacket& recvData) +void WorldSession::HandleCalendarEventRemoveInvite(WorldPackets::Calendar::CalendarRemoveInvite& calendarRemoveInvite) { ObjectGuid guid = _player->GetGUID(); - ObjectGuid invitee; - uint64 eventId; - uint64 ownerInviteId; // isn't it sender's inviteId? - uint64 inviteId; - - recvData >> invitee.ReadAsPacked(); - recvData >> inviteId >> ownerInviteId >> eventId; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_REMOVE_INVITE [{}] EventId [{}], ownerInviteId [{}], Invitee ([{}] id: [{}])", - guid.ToString(), eventId, ownerInviteId, invitee.ToString(), inviteId); + TC_LOG_DEBUG("network", "CMSG_CALENDAR_REMOVE_INVITE [{}] EventId [{}], ownerInviteId [{}], Invitee ([{}] id: [{}])", + guid.ToString(), calendarRemoveInvite.EventID, calendarRemoveInvite.ModeratorID, calendarRemoveInvite.Guid.ToString(), calendarRemoveInvite.InviteID); - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarRemoveInvite.EventID)) { - if (calendarEvent->GetCreatorGUID() == invitee) + if (calendarEvent->GetOwnerGUID() == calendarRemoveInvite.Guid) { sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_DELETE_CREATOR_FAILED); return; } - sCalendarMgr->RemoveInvite(inviteId, eventId, guid); + sCalendarMgr->RemoveInvite(calendarRemoveInvite.InviteID, calendarRemoveInvite.EventID, guid); } else sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_NO_INVITE); } -void WorldSession::HandleCalendarEventStatus(WorldPacket& recvData) +void WorldSession::HandleCalendarEventStatus(WorldPackets::Calendar::CalendarStatus& calendarStatus) { ObjectGuid guid = _player->GetGUID(); - ObjectGuid invitee; - uint64 eventId; - uint64 inviteId; - uint64 ownerInviteId; // isn't it sender's inviteId? - uint8 status; - - recvData >> invitee.ReadAsPacked(); - recvData >> eventId >> inviteId >> ownerInviteId >> status; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_STATUS [{}] EventId [{}] ownerInviteId [{}], Invitee ([{}] id: [{}], status {}", - guid.ToString(), eventId, ownerInviteId, invitee.ToString(), inviteId, status); - - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + + TC_LOG_DEBUG("network", "CMSG_CALENDAR_STATUS [{}] EventId [{}] ownerInviteId [{}], Invitee ([{}] id: [{}], status {}", + guid.ToString(), calendarStatus.EventID, calendarStatus.ModeratorID, calendarStatus.Guid.ToString(), calendarStatus.InviteID, calendarStatus.Status); + + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarStatus.EventID)) { - if (CalendarInvite* invite = sCalendarMgr->GetInvite(inviteId)) + if (CalendarInvite* invite = sCalendarMgr->GetInvite(calendarStatus.InviteID)) { - invite->SetStatus((CalendarInviteStatus)status); - // not sure if we should set response time when moderator changes invite status - //invite->SetStatusTime(time(nullptr)); + invite->SetStatus((CalendarInviteStatus)calendarStatus.Status); sCalendarMgr->UpdateInvite(invite); sCalendarMgr->SendCalendarEventStatus(*calendarEvent, *invite); - sCalendarMgr->SendCalendarClearPendingAction(invitee); + sCalendarMgr->SendCalendarClearPendingAction(calendarStatus.Guid); } else sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_NO_INVITE); // correct? @@ -724,25 +572,19 @@ void WorldSession::HandleCalendarEventStatus(WorldPacket& recvData) sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recvData) +void WorldSession::HandleCalendarEventModeratorStatus(WorldPackets::Calendar::CalendarModeratorStatusQuery& calendarModeratorStatus) { ObjectGuid guid = _player->GetGUID(); - ObjectGuid invitee; - uint64 eventId; - uint64 inviteId; - uint64 ownerInviteId; // isn't it sender's inviteId? - uint8 rank; - - recvData >> invitee.ReadAsPacked(); - recvData >> eventId >> inviteId >> ownerInviteId >> rank; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_EVENT_MODERATOR_STATUS [{}] EventId [{}] ownerInviteId [{}], Invitee ([{}] id: [{}], rank {}", - guid.ToString(), eventId, ownerInviteId, invitee.ToString(), inviteId, rank); - - if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(eventId)) + + TC_LOG_DEBUG("network", "CMSG_CALENDAR_MODERATOR_STATUS [{}] EventID [{}] ModeratorID [{}], Invitee ([{}] InviteID: [{}], Status {}", + guid.ToString(), calendarModeratorStatus.EventID, calendarModeratorStatus.ModeratorID, calendarModeratorStatus.Guid.ToString(), calendarModeratorStatus.InviteID, + calendarModeratorStatus.Status); + + if (CalendarEvent* calendarEvent = sCalendarMgr->GetEvent(calendarModeratorStatus.EventID)) { - if (CalendarInvite* invite = sCalendarMgr->GetInvite(inviteId)) + if (CalendarInvite* invite = sCalendarMgr->GetInvite(calendarModeratorStatus.InviteID)) { - invite->SetRank(CalendarModerationRank(rank)); + invite->SetRank(CalendarModerationRank(calendarModeratorStatus.Status)); sCalendarMgr->UpdateInvite(invite); sCalendarMgr->SendCalendarEventModeratorStatusAlert(*calendarEvent, *invite); } @@ -753,46 +595,37 @@ void WorldSession::HandleCalendarEventModeratorStatus(WorldPacket& recvData) sCalendarMgr->SendCalendarCommandResult(guid, CALENDAR_ERROR_EVENT_INVALID); } -void WorldSession::HandleCalendarComplain(WorldPacket& recvData) +void WorldSession::HandleCalendarComplain(WorldPackets::Calendar::CalendarComplain& calendarComplain) { ObjectGuid guid = _player->GetGUID(); - uint64 eventId; - ObjectGuid complainGUID; - - recvData >> eventId >> complainGUID; - TC_LOG_DEBUG("network", "CMSG_CALENDAR_COMPLAIN [{}] EventId [{}] guid [{}]", - guid.ToString(), eventId, complainGUID.ToString()); + TC_LOG_DEBUG("network", "CMSG_CALENDAR_COMPLAIN [{}] EventId [{}] guid [{}] InviteId [{}]", guid.ToString(), calendarComplain.EventID, + calendarComplain.InvitedByGUID.ToString(), calendarComplain.InviteID); // what to do with complains? } -void WorldSession::HandleCalendarGetNumPending(WorldPacket& /*recvData*/) +void WorldSession::HandleCalendarGetNumPending(WorldPackets::Calendar::CalendarGetNumPending& /*calendarGetNumPending*/) { ObjectGuid guid = _player->GetGUID(); uint32 pending = sCalendarMgr->GetPlayerNumPending(guid); TC_LOG_DEBUG("network", "CMSG_CALENDAR_GET_NUM_PENDING: [{}] Pending: {}", guid.ToString(), pending); - WorldPacket data(SMSG_CALENDAR_SEND_NUM_PENDING, 4); - data << uint32(pending); - SendPacket(&data); + SendPacket(WorldPackets::Calendar::CalendarSendNumPending(pending).Write()); } -void WorldSession::HandleSetSavedInstanceExtend(WorldPacket& recvData) +void WorldSession::HandleSetSavedInstanceExtend(WorldPackets::Calendar::SetSavedInstanceExtend& setSavedInstanceExtend) { - uint32 mapId, difficulty; - uint8 toggleExtend; - recvData >> mapId >> difficulty>> toggleExtend; - TC_LOG_DEBUG("network", "CMSG_SET_SAVED_INSTANCE_EXTEND - MapId: {}, Difficulty: {}, ToggleExtend: {}", mapId, difficulty, toggleExtend ? "On" : "Off"); + TC_LOG_DEBUG("network", "CMSG_SET_SAVED_INSTANCE_EXTEND - MapId: {}, Difficulty: {}, ToggleExtend: {}", setSavedInstanceExtend.MapID, setSavedInstanceExtend.DifficultyID, setSavedInstanceExtend.Extend ? "On" : "Off"); if (Player* player = GetPlayer()) { - InstancePlayerBind* instanceBind = player->GetBoundInstance(mapId, Difficulty(difficulty), toggleExtend == 1); // include expired instances if we are toggling extend on + InstancePlayerBind* instanceBind = player->GetBoundInstance(setSavedInstanceExtend.MapID, Difficulty(setSavedInstanceExtend.DifficultyID), setSavedInstanceExtend.Extend); // include expired instances if we are toggling extend on if (!instanceBind || !instanceBind->save || !instanceBind->perm) return; BindExtensionState newState; - if (!toggleExtend || instanceBind->extendState == EXTEND_STATE_EXPIRED) + if (!setSavedInstanceExtend.Extend || instanceBind->extendState == EXTEND_STATE_EXPIRED) newState = EXTEND_STATE_NORMAL; else newState = EXTEND_STATE_EXTENDED; @@ -813,23 +646,25 @@ void WorldSession::HandleSetSavedInstanceExtend(WorldPacket& recvData) // ----------------------------------- SEND ------------------------------------ -void WorldSession::SendCalendarRaidLockout(InstanceSave const* save, bool add) +void WorldSession::SendCalendarRaidLockoutAdded(InstanceSave const* save) { - TC_LOG_DEBUG("network", "{}", add ? "SMSG_CALENDAR_RAID_LOCKOUT_ADDED" : "SMSG_CALENDAR_RAID_LOCKOUT_REMOVED"); - time_t currTime = GameTime::GetGameTime(); - - WorldPacket data(SMSG_CALENDAR_RAID_LOCKOUT_REMOVED, (4) + 4 + 4 + 4 + 8); - if (add) - { - data.SetOpcode(SMSG_CALENDAR_RAID_LOCKOUT_ADDED); - data.AppendPackedTime(currTime); - } + WorldPackets::Calendar::CalendarRaidLockoutAdded calendarRaidLockoutAdded; + calendarRaidLockoutAdded.InstanceID = save->GetInstanceId(); + calendarRaidLockoutAdded.ServerTime = *GameTime::GetWowTime(); + calendarRaidLockoutAdded.MapID = int32(save->GetMapId()); + calendarRaidLockoutAdded.DifficultyID = save->GetDifficulty(); + calendarRaidLockoutAdded.TimeRemaining = int32(save->GetResetTime() - GameTime::GetGameTime()); + SendPacket(calendarRaidLockoutAdded.Write()); +} - data << uint32(save->GetMapId()); - data << uint32(save->GetDifficulty()); - data << uint32(save->GetResetTime() - currTime); - data << uint64(save->GetInstanceId()); - SendPacket(&data); +void WorldSession::SendCalendarRaidLockoutRemoved(InstanceSave const* save) +{ + WorldPackets::Calendar::CalendarRaidLockoutRemoved calendarRaidLockoutRemoved; + calendarRaidLockoutRemoved.InstanceID = save->GetInstanceId(); + calendarRaidLockoutRemoved.MapID = int32(save->GetMapId()); + calendarRaidLockoutRemoved.DifficultyID = save->GetDifficulty(); + calendarRaidLockoutRemoved.TimeRemaining = int32(save->GetResetTime() - GameTime::GetGameTime()); + SendPacket(calendarRaidLockoutRemoved.Write()); } void WorldSession::SendCalendarRaidLockoutUpdated(InstanceSave const* save) @@ -841,13 +676,11 @@ void WorldSession::SendCalendarRaidLockoutUpdated(InstanceSave const* save) TC_LOG_DEBUG("network", "SMSG_CALENDAR_RAID_LOCKOUT_UPDATED [{}] Map: {}, Difficulty {}", guid.ToString(), save->GetMapId(), static_cast<uint32>(save->GetDifficulty())); - time_t currTime = GameTime::GetGameTime(); - - WorldPacket data(SMSG_CALENDAR_RAID_LOCKOUT_UPDATED, 4 + 4 + 4 + 4 + 8); - data.AppendPackedTime(currTime); - data << uint32(save->GetMapId()); - data << uint32(save->GetDifficulty()); - data << uint32(0); // Amount of seconds that has changed to the reset time - data << uint32(save->GetResetTime() - currTime); - SendPacket(&data); + WorldPackets::Calendar::CalendarRaidLockoutUpdated calendarRaidLockoutUpdated; + calendarRaidLockoutUpdated.ServerTime = *GameTime::GetWowTime(); + calendarRaidLockoutUpdated.MapID = save->GetMapId(); + calendarRaidLockoutUpdated.DifficultyID = save->GetDifficulty(); + calendarRaidLockoutUpdated.OldTimeRemaining = 0; + calendarRaidLockoutUpdated.NewTimeRemaining = std::max(save->GetResetTime() - GameTime::GetGameTime(), SI64LIT(0)); + SendPacket(calendarRaidLockoutUpdated.Write()); } diff --git a/src/server/game/Maps/Map.cpp b/src/server/game/Maps/Map.cpp index 303178adc9c..10d3f1df348 100644 --- a/src/server/game/Maps/Map.cpp +++ b/src/server/game/Maps/Map.cpp @@ -4154,7 +4154,7 @@ void InstanceMap::PermBindAllPlayers() WorldPacket data(SMSG_INSTANCE_SAVE_CREATED, 4); data << uint32(0); player->SendDirectMessage(&data); - player->GetSession()->SendCalendarRaidLockout(save, true); + player->GetSession()->SendCalendarRaidLockoutAdded(save); // if group leader is in instance, group also gets bound if (Group* group = player->GetGroup()) diff --git a/src/server/game/Server/Packets/AllPackets.h b/src/server/game/Server/Packets/AllPackets.h index 12f1fb37973..1c4d55272ff 100644 --- a/src/server/game/Server/Packets/AllPackets.h +++ b/src/server/game/Server/Packets/AllPackets.h @@ -19,6 +19,7 @@ #define AllPackets_h__ #include "BankPackets.h" +#include "CalendarPackets.h" #include "CharacterPackets.h" #include "ChatPackets.h" #include "CombatLogPackets.h" diff --git a/src/server/game/Server/Packets/CalendarPackets.cpp b/src/server/game/Server/Packets/CalendarPackets.cpp new file mode 100644 index 00000000000..dbc96106126 --- /dev/null +++ b/src/server/game/Server/Packets/CalendarPackets.cpp @@ -0,0 +1,471 @@ +/*
+ * 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 "CalendarPackets.h"
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarEventInfo const& eventInfo)
+{
+ data << uint64(eventInfo.EventID);
+ data << eventInfo.EventName;
+ data << uint32(eventInfo.EventType);
+ data << eventInfo.Date;
+ data << uint32(eventInfo.Flags);
+ data << int32(eventInfo.TextureID);
+ data << eventInfo.OwnerGuid.WriteAsPacked();
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarRaidLockoutInfo const& lockoutInfo)
+{
+ data << int32(lockoutInfo.MapID);
+ data << uint32(lockoutInfo.DifficultyID);
+ data << int32(lockoutInfo.ExpireTime);
+ data << uint64(lockoutInfo.InstanceID);
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarInviteInfo const& inviteInfo)
+{
+ data << uint64(inviteInfo.EventID);
+ data << uint64(inviteInfo.InviteID);
+ data << uint8(inviteInfo.Status);
+ data << uint8(inviteInfo.Moderator);
+ data << uint8(inviteInfo.InviteType);
+ data << inviteInfo.InviterGuid.WriteAsPacked();
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarHolidayInfo const& holidayInfo)
+{
+ data << uint32(holidayInfo.HolidayID);
+ data << uint32(holidayInfo.Region);
+ data << uint32(holidayInfo.Looping);
+ data << uint32(holidayInfo.Priority);
+ data << uint32(holidayInfo.FilterType);
+
+ for (uint8 j = 0; j < MAX_HOLIDAY_DATES; ++j)
+ data << holidayInfo.Date[j];
+
+ data.append(holidayInfo.Duration.data(), holidayInfo.Duration.size());
+ data.append(holidayInfo.CalendarFlags.data(), holidayInfo.CalendarFlags.size());
+
+ data << holidayInfo.TextureFilename;
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarSendCalendarRaidResetInfo const& raidResetInfo)
+{
+ data << int32(raidResetInfo.MapID);
+ data << int32(raidResetInfo.Duration);
+ data << int32(raidResetInfo.Offset);
+
+ return data;
+}
+
+ByteBuffer& operator<<(ByteBuffer& data, WorldPackets::Calendar::CalendarEventInviteInfo const& inviteInfo)
+{
+ data << inviteInfo.Guid.WriteAsPacked();
+ data << uint8(inviteInfo.Level);
+ data << uint8(inviteInfo.Status);
+ data << uint8(inviteInfo.Moderator);
+ data << uint8(inviteInfo.InviteType);
+ data << uint64(inviteInfo.InviteID);
+ data << inviteInfo.ResponseTime;
+ data << inviteInfo.Notes;
+
+ return data;
+}
+
+void WorldPackets::Calendar::CalendarGetEvent::Read()
+{
+ _worldPacket >> EventID;
+}
+
+void WorldPackets::Calendar::CalendarGuildFilter::Read()
+{
+ _worldPacket >> MinLevel;
+ _worldPacket >> MaxLevel;
+ _worldPacket >> MaxRankOrder;
+}
+
+void WorldPackets::Calendar::CalendarArenaTeam::Read()
+{
+ _worldPacket >> ArenaTeamId;
+}
+
+ByteBuffer& operator>>(ByteBuffer& buffer, WorldPackets::Calendar::CalendarAddEventInviteInfo& invite)
+{
+ buffer >> invite.Guid.ReadAsPacked();
+ buffer >> invite.Status;
+ buffer >> invite.Moderator;
+
+ return buffer;
+}
+
+void WorldPackets::Calendar::CalendarAddEvent::Read()
+{
+ _worldPacket >> Title;
+ _worldPacket >> Description;
+ _worldPacket >> EventType;
+ _worldPacket.read_skip<uint8>(); // Repeatable
+ _worldPacket >> MaxSize;
+ _worldPacket >> TextureID;
+ _worldPacket >> Time;
+ _worldPacket >> LockDate;
+ _worldPacket >> Flags;
+ Invites.resize(_worldPacket.read<uint32>());
+ for (CalendarAddEventInviteInfo& invite : Invites)
+ _worldPacket >> invite;
+}
+
+void WorldPackets::Calendar::CalendarUpdateEvent::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> Title;
+ _worldPacket >> Description;
+ _worldPacket >> EventType;
+ _worldPacket.read_skip<uint8>(); // Repeatable
+ _worldPacket >> MaxSize;
+ _worldPacket >> TextureID;
+ _worldPacket >> Time;
+ _worldPacket >> LockDate;
+ _worldPacket >> Flags;
+}
+
+void WorldPackets::Calendar::CalendarRemoveEvent::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> IsSignUp;
+}
+
+void WorldPackets::Calendar::CalendarCopyEvent::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> Date;
+}
+
+void WorldPackets::Calendar::CalendarRSVP::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> InviteID;
+ _worldPacket >> Status;
+}
+
+void WorldPackets::Calendar::CalendarInvite::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> Name;
+ _worldPacket >> Creating;
+ _worldPacket >> IsSignUp;
+}
+
+void WorldPackets::Calendar::CalendarEventSignUp::Read()
+{
+ _worldPacket >> EventID;
+ _worldPacket >> Tentative;
+}
+
+void WorldPackets::Calendar::CalendarRemoveInvite::Read()
+{
+ _worldPacket >> Guid.ReadAsPacked();
+ _worldPacket >> InviteID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> EventID;
+}
+
+void WorldPackets::Calendar::CalendarStatus::Read()
+{
+ _worldPacket >> Guid.ReadAsPacked();
+ _worldPacket >> EventID;
+ _worldPacket >> InviteID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> Status;
+}
+
+void WorldPackets::Calendar::SetSavedInstanceExtend::Read()
+{
+ _worldPacket >> MapID;
+ _worldPacket >> DifficultyID;
+ _worldPacket >> Extend;
+}
+
+void WorldPackets::Calendar::CalendarModeratorStatusQuery::Read()
+{
+ _worldPacket >> Guid.ReadAsPacked();
+ _worldPacket >> EventID;
+ _worldPacket >> InviteID;
+ _worldPacket >> ModeratorID;
+ _worldPacket >> Status;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteAdded::Write()
+{
+ _worldPacket << InviteGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << uint64(InviteID);
+ _worldPacket << uint8(Level);
+ _worldPacket << uint8(Status);
+ _worldPacket << uint8(Type);
+ if (Type == 1)
+ _worldPacket << ResponseTime;
+
+ _worldPacket << uint8(ClearPending);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarSendCalendar::Write()
+{
+ _worldPacket << uint32(Invites.size());
+ for (CalendarSendCalendarInviteInfo const& invite : Invites)
+ _worldPacket << invite;
+
+ _worldPacket << uint32(Events.size());
+ for (CalendarSendCalendarEventInfo const& event : Events)
+ _worldPacket << event;
+
+ _worldPacket << uint32(ServerNow);
+ _worldPacket << ServerTime;
+
+ _worldPacket << uint32(RaidLockouts.size());
+ for (CalendarSendCalendarRaidLockoutInfo const& lockout : RaidLockouts)
+ _worldPacket << lockout;
+
+ _worldPacket << uint32(RaidOrigin);
+
+ _worldPacket << uint32(RaidResets.size());
+ for (CalendarSendCalendarRaidResetInfo const& reset : RaidResets)
+ _worldPacket << reset;
+
+ _worldPacket << uint32(Holidays.size());
+ for (CalendarSendCalendarHolidayInfo const& holiday : Holidays)
+ _worldPacket << holiday;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarSendEvent::Write()
+{
+ _worldPacket << uint8(EventType);
+ _worldPacket << OwnerGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << EventName;
+ _worldPacket << Description;
+ _worldPacket << uint8(GetEventType);
+ _worldPacket << uint8(CALENDAR_REPEAT_NEVER); // repeatable
+ _worldPacket << uint32(CALENDAR_MAX_INVITES);
+ _worldPacket << int32(TextureID);
+ _worldPacket << uint32(Flags);
+ _worldPacket << Date;
+ _worldPacket << LockDate;
+ _worldPacket << uint32(EventGuildID);
+ _worldPacket << uint32(Invites.size());
+ for (CalendarEventInviteInfo const& invite : Invites)
+ _worldPacket << invite;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteAlert::Write()
+{
+ _worldPacket << uint64(EventID);
+ _worldPacket << EventName;
+ _worldPacket << Date;
+ _worldPacket << uint32(Flags);
+ _worldPacket << uint32(EventType);
+ _worldPacket << int32(TextureID);
+ _worldPacket << uint64(InviteID);
+ _worldPacket << uint8(Status);
+ _worldPacket << uint8(ModeratorStatus);
+ _worldPacket << OwnerGuid.WriteAsPacked();
+ _worldPacket << InvitedByGuid.WriteAsPacked();
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteStatus::Write()
+{
+ _worldPacket << InviteGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << Date;
+ _worldPacket << uint32(Flags);
+ _worldPacket << uint8(Status);
+ _worldPacket << uint8(ClearPending);
+ _worldPacket << ResponseTime;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteRemoved::Write()
+{
+ _worldPacket << InviteGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << uint32(Flags);
+ _worldPacket << uint8(ClearPending);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarModeratorStatus::Write()
+{
+ _worldPacket << InviteGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << uint8(Status);
+ _worldPacket << uint8(ClearPending);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteRemovedAlert::Write()
+{
+ _worldPacket << uint64(EventID);
+ _worldPacket << Date;
+ _worldPacket << uint32(Flags);
+ _worldPacket << uint8(Status);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarEventUpdatedAlert::Write()
+{
+ _worldPacket << uint8(ClearPending);
+ _worldPacket << uint64(EventID);
+ _worldPacket << OriginalDate;
+ _worldPacket << uint32(Flags);
+ _worldPacket << Date;
+ _worldPacket << uint8(EventType);
+ _worldPacket << uint32(TextureID);
+ _worldPacket << EventName;
+ _worldPacket << Description;
+ _worldPacket << uint8(CALENDAR_REPEAT_NEVER); // repeatable
+ _worldPacket << uint32(CALENDAR_MAX_INVITES);
+ _worldPacket << LockDate;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarEventRemovedAlert::Write()
+{
+ _worldPacket << uint8(ClearPending);
+ _worldPacket << uint64(EventID);
+ _worldPacket << Date;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarSendNumPending::Write()
+{
+ _worldPacket << uint32(NumPending);
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarCommandResult::Write()
+{
+ _worldPacket << uint32(Command);
+ _worldPacket << "";
+ _worldPacket << Name;
+ _worldPacket << uint32(Result);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutAdded::Write()
+{
+ _worldPacket << ServerTime;
+ _worldPacket << int32(MapID);
+ _worldPacket << uint32(DifficultyID);
+ _worldPacket << int32(TimeRemaining);
+ _worldPacket << uint64(InstanceID);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutRemoved::Write()
+{
+ _worldPacket << int32(MapID);
+ _worldPacket << uint32(DifficultyID);
+ _worldPacket << int32(TimeRemaining);
+ _worldPacket << uint64(InstanceID);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarRaidLockoutUpdated::Write()
+{
+ _worldPacket << ServerTime;
+ _worldPacket << int32(MapID);
+ _worldPacket << uint32(DifficultyID);
+ _worldPacket << int32(OldTimeRemaining);
+ _worldPacket << int32(NewTimeRemaining);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarEventInitialInvites::Write()
+{
+ _worldPacket << uint32(Invites.size());
+ for (CalendarEventInitialInviteInfo const& invite : Invites)
+ {
+ _worldPacket << invite.InviteGuid.WriteAsPacked();
+ _worldPacket << uint8(invite.Level);
+ }
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteStatusAlert::Write()
+{
+ _worldPacket << uint64(EventID);
+ _worldPacket << Date;
+ _worldPacket << uint32(Flags);
+ _worldPacket << uint8(Status);
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteNotesAlert::Write()
+{
+ _worldPacket << uint64(EventID);
+ _worldPacket << Notes;
+
+ return &_worldPacket;
+}
+
+WorldPacket const* WorldPackets::Calendar::CalendarInviteNotes::Write()
+{
+ _worldPacket << InviteGuid.WriteAsPacked();
+ _worldPacket << uint64(EventID);
+ _worldPacket << Notes;
+ _worldPacket << uint8(ClearPending);
+
+ return &_worldPacket;
+}
+
+void WorldPackets::Calendar::CalendarComplain::Read()
+{
+ _worldPacket >> InvitedByGUID;
+ _worldPacket >> EventID;
+ _worldPacket >> InviteID;
+}
diff --git a/src/server/game/Server/Packets/CalendarPackets.h b/src/server/game/Server/Packets/CalendarPackets.h new file mode 100644 index 00000000000..fd6afc79ad3 --- /dev/null +++ b/src/server/game/Server/Packets/CalendarPackets.h @@ -0,0 +1,605 @@ +/* + * 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 CalendarPackets_h__ +#define CalendarPackets_h__ + +#include "Packet.h" +#include "CalendarMgr.h" +#include "DBCStructure.h" +#include "ObjectGuid.h" +#include "Optional.h" +#include "PacketUtilities.h" +#include "WowTime.h" + +namespace WorldPackets +{ + namespace Calendar + { + class CalendarGetCalendar final : public ClientPacket + { + public: + CalendarGetCalendar(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_GET_CALENDAR, std::move(packet)) { } + + void Read() override { } + }; + + class CalendarGetEvent final : public ClientPacket + { + public: + CalendarGetEvent(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_GET_EVENT, std::move(packet)) { } + + void Read() override; + + uint64 EventID = 0; + }; + + class CalendarGuildFilter final : public ClientPacket + { + public: + CalendarGuildFilter(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_GUILD_FILTER, std::move(packet)) { } + + void Read() override; + + uint32 MinLevel = 1; + uint32 MaxLevel = 100; + uint32 MaxRankOrder = 0; + }; + + class CalendarArenaTeam final : public ClientPacket + { + public: + CalendarArenaTeam(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_ARENA_TEAM, std::move(packet)) { } + + void Read() override; + + uint32 ArenaTeamId = 0; + }; + + struct CalendarAddEventInviteInfo + { + ObjectGuid Guid; + uint8 Status = 0; + uint8 Moderator = 0; + }; + + class CalendarAddEvent final : public ClientPacket + { + public: + CalendarAddEvent(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_ADD_EVENT, std::move(packet)) { } + + void Read() override; + + uint32 MaxSize = 100; + std::string Title; + std::string Description; + uint8 EventType = 0; + int32 TextureID = 0; + WowTime Time; + WowTime LockDate; + uint32 Flags = 0; + Array<CalendarAddEventInviteInfo, CALENDAR_MAX_INVITES> Invites; + }; + + class CalendarUpdateEvent final : public ClientPacket + { + public: + CalendarUpdateEvent(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_UPDATE_EVENT, std::move(packet)) { } + + void Read() override; + + uint64 EventID = 0; + uint64 ModeratorID = 0; + std::string Title; + std::string Description; + uint8 EventType = 0; + uint32 TextureID = 0; + WowTime Time; + WowTime LockDate; + uint32 Flags = 0; + uint32 MaxSize = 0; + }; + + class CalendarRemoveEvent final : public ClientPacket + { + public: + CalendarRemoveEvent(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_REMOVE_EVENT, std::move(packet)) { } + + void Read() override; + + uint64 ModeratorID = 0; + uint64 EventID = 0; + bool IsSignUp = false; + }; + + class CalendarCopyEvent final : public ClientPacket + { + public: + CalendarCopyEvent(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_COPY_EVENT, std::move(packet)) { } + + void Read() override; + + uint64 ModeratorID = 0; + uint64 EventID = 0; + WowTime Date; + }; + + class CalendarInviteAdded final : public ServerPacket + { + public: + CalendarInviteAdded() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE, 43) { } + + WorldPacket const* Write() override; + + uint64 InviteID = 0; + WowTime ResponseTime; + uint8 Level = 100; + ObjectGuid InviteGuid; + uint64 EventID = 0; + uint8 Type = 0; + bool ClearPending = false; + uint8 Status = 0; + }; + + struct CalendarSendCalendarInviteInfo + { + uint64 EventID = 0; + uint64 InviteID = 0; + ObjectGuid InviterGuid; + uint8 Status = 0; + uint8 Moderator = 0; + uint8 InviteType = 0; + bool IgnoreFriendAndGuildRestriction = false; + }; + + struct CalendarSendCalendarRaidLockoutInfo + { + uint64 InstanceID = 0; + int32 MapID = 0; + uint32 DifficultyID = 0; + int32 ExpireTime = 0; + }; + + struct CalendarSendCalendarEventInfo + { + uint64 EventID = 0; + std::string EventName; + uint8 EventType = 0; + WowTime Date; + uint32 Flags = 0; + int32 TextureID = 0; + ObjectGuid OwnerGuid; + }; + + struct CalendarSendCalendarRaidResetInfo + { + int32 MapID = 0; + uint32 Duration = 0; + int32 Offset = 0; + }; + + struct CalendarSendCalendarHolidayInfo + { + int32 HolidayID = 0; + int32 Region = 0; + int32 Looping = 0; + int32 Priority = 0; + int32 FilterType = 0; + std::string_view TextureFilename; + std::array<WowTime, MAX_HOLIDAY_DATES> Date = { }; + std::array<int32, MAX_HOLIDAY_DURATIONS> Duration = { }; + std::array<int32, MAX_HOLIDAY_FLAGS> CalendarFlags = { }; + }; + + class CalendarSendCalendar final : public ServerPacket + { + public: + CalendarSendCalendar() : ServerPacket(SMSG_CALENDAR_SEND_CALENDAR, 338) { } + + WorldPacket const* Write() override; + + WowTime ServerTime; + std::vector<CalendarSendCalendarInviteInfo> Invites; + std::vector<CalendarSendCalendarRaidLockoutInfo> RaidLockouts; + std::vector<CalendarSendCalendarEventInfo> Events; + time_t ServerNow = time_t(0); + time_t RaidOrigin = time_t(0); + std::vector<CalendarSendCalendarRaidResetInfo> RaidResets; + std::vector<CalendarSendCalendarHolidayInfo> Holidays; + }; + + struct CalendarEventInviteInfo + { + ObjectGuid Guid; + uint64 InviteID = 0; + WowTime ResponseTime; + uint8 Level = 1; + uint8 Status = 0; + uint8 Moderator = 0; + uint8 InviteType = 0; + std::string Notes; + }; + + class CalendarSendEvent final : public ServerPacket + { + public: + CalendarSendEvent() : ServerPacket(SMSG_CALENDAR_SEND_EVENT, 93) { } + + WorldPacket const* Write() override; + + ObjectGuid OwnerGuid; + ObjectGuid::LowType EventGuildID = 0; + uint64 EventID = 0; + WowTime Date; + WowTime LockDate; + uint32 Flags = 0; + int32 TextureID = 0; + uint8 GetEventType = 0; + uint8 EventType = 0; + std::string Description; + std::string EventName; + std::vector<CalendarEventInviteInfo> Invites; + }; + + class CalendarInviteAlert final : public ServerPacket + { + public: + CalendarInviteAlert() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_ALERT, 80) { } + + WorldPacket const* Write() override; + + ObjectGuid OwnerGuid; + ObjectGuid InvitedByGuid; + uint64 InviteID = 0; + uint64 EventID = 0; + uint32 Flags = 0; + WowTime Date; + int32 TextureID = 0; + uint8 Status = 0; + uint32 EventType = 0; + uint8 ModeratorStatus = 0; + std::string EventName; + }; + + class CalendarInvite final : public ClientPacket + { + public: + CalendarInvite(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_INVITE, std::move(packet)) { } + + void Read() override; + + uint64 ModeratorID = 0; + bool IsSignUp = false; + bool Creating = true; + uint64 EventID = 0; + std::string Name; + }; + + class CalendarRSVP final : public ClientPacket + { + public: + CalendarRSVP(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_RSVP, std::move(packet)) { } + + void Read() override; + + uint64 InviteID = 0; + uint64 EventID = 0; + uint8 Status = 0; + }; + + class CalendarInviteStatus final : public ServerPacket + { + public: + CalendarInviteStatus() : ServerPacket(SMSG_CALENDAR_EVENT_STATUS, 41) { } + + WorldPacket const* Write() override; + + uint32 Flags = 0; + uint64 EventID = 0; + uint8 Status = 0; + bool ClearPending = false; + WowTime ResponseTime; + WowTime Date; + ObjectGuid InviteGuid; + }; + + class CalendarInviteRemoved final : public ServerPacket + { + public: + CalendarInviteRemoved() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_REMOVED, 29) { } + + WorldPacket const* Write() override; + + ObjectGuid InviteGuid; + uint64 EventID = 0; + uint32 Flags = 0; + bool ClearPending = false; + }; + + class CalendarModeratorStatus final : public ServerPacket + { + public: + CalendarModeratorStatus() : ServerPacket(SMSG_CALENDAR_EVENT_MODERATOR_STATUS_ALERT, 26) { } + + WorldPacket const* Write() override; + + ObjectGuid InviteGuid; + uint64 EventID = 0; + uint8 Status = 0; + bool ClearPending = false; + }; + + class CalendarInviteRemovedAlert final : public ServerPacket + { + public: + CalendarInviteRemovedAlert() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_REMOVED_ALERT, 17) { } + + WorldPacket const* Write() override; + + uint64 EventID = 0; + WowTime Date; + uint32 Flags = 0; + uint8 Status = 0; + }; + + class CalendarClearPendingAction final : public ServerPacket + { + public: + CalendarClearPendingAction() : ServerPacket(SMSG_CALENDAR_CLEAR_PENDING_ACTION, 0) { } + + WorldPacket const* Write() override { return &_worldPacket; } + }; + + class CalendarEventUpdatedAlert final : public ServerPacket + { + public: + CalendarEventUpdatedAlert() : ServerPacket(SMSG_CALENDAR_EVENT_UPDATED_ALERT, 32) { } + + WorldPacket const* Write() override; + + uint64 EventID = 0; + WowTime Date; + uint32 Flags = 0; + WowTime LockDate; + WowTime OriginalDate; + int32 TextureID = 0; + uint8 EventType = 0; + bool ClearPending = false; + std::string Description; + std::string EventName; + }; + + class CalendarEventRemovedAlert final : public ServerPacket + { + public: + CalendarEventRemovedAlert() : ServerPacket(SMSG_CALENDAR_EVENT_REMOVED_ALERT, 13) { } + + WorldPacket const* Write() override; + + uint64 EventID = 0; + WowTime Date; + bool ClearPending = false; + }; + + class CalendarSendNumPending final : public ServerPacket + { + public: + CalendarSendNumPending() : ServerPacket(SMSG_CALENDAR_SEND_NUM_PENDING, 4) { } + CalendarSendNumPending(uint32 numPending) : ServerPacket(SMSG_CALENDAR_SEND_NUM_PENDING, 4), NumPending(numPending) { } + + WorldPacket const* Write() override; + + uint32 NumPending = 0; + }; + + class CalendarGetNumPending final : public ClientPacket + { + public: + CalendarGetNumPending(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_GET_NUM_PENDING, std::move(packet)) { } + + void Read() override { } + }; + + class CalendarEventSignUp final : public ClientPacket + { + public: + CalendarEventSignUp(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_SIGNUP, std::move(packet)) { } + + void Read() override; + + bool Tentative = false; + uint64 EventID = 0; + }; + + class CalendarRemoveInvite final : public ClientPacket + { + public: + CalendarRemoveInvite(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_REMOVE_INVITE, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + uint64 EventID = 0; + uint64 ModeratorID = 0; + uint64 InviteID = 0; + }; + + class CalendarStatus final : public ClientPacket + { + public: + CalendarStatus(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_STATUS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + uint64 EventID = 0; + uint64 ModeratorID = 0; + uint64 InviteID = 0; + uint8 Status = 0; + }; + + class SetSavedInstanceExtend final : public ClientPacket + { + public: + SetSavedInstanceExtend(WorldPacket&& packet) : ClientPacket(CMSG_SET_SAVED_INSTANCE_EXTEND, std::move(packet)) { } + + void Read() override; + + int32 MapID = 0; + bool Extend = false; + uint32 DifficultyID = 0; + }; + + class CalendarModeratorStatusQuery final : public ClientPacket + { + public: + CalendarModeratorStatusQuery(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_EVENT_MODERATOR_STATUS, std::move(packet)) { } + + void Read() override; + + ObjectGuid Guid; + uint64 EventID = 0; + uint64 InviteID = 0; + uint64 ModeratorID = 0; + uint8 Status = 0; + }; + + class CalendarCommandResult final : public ServerPacket + { + public: + CalendarCommandResult() : ServerPacket(SMSG_CALENDAR_COMMAND_RESULT, 3) { } + CalendarCommandResult(uint8 command, uint8 result, std::string const& name) : ServerPacket(SMSG_CALENDAR_COMMAND_RESULT, 3), Command(command), Result(result), Name(name) { } + + WorldPacket const* Write() override; + + uint32 Command = 0; + uint32 Result = 0; + std::string Name; + }; + + class CalendarRaidLockoutAdded final : public ServerPacket + { + public: + CalendarRaidLockoutAdded() : ServerPacket(SMSG_CALENDAR_RAID_LOCKOUT_ADDED, 8 + 4 + 4 + 4 + 4) { } + + WorldPacket const* Write() override; + + uint64 InstanceID = 0; + uint32 DifficultyID = 0; + int32 TimeRemaining = 0; + WowTime ServerTime; + int32 MapID = 0; + }; + + class CalendarRaidLockoutRemoved final : public ServerPacket + { + public: + CalendarRaidLockoutRemoved() : ServerPacket(SMSG_CALENDAR_RAID_LOCKOUT_REMOVED, 8 + 4 + 4) { } + + WorldPacket const* Write() override; + + uint64 InstanceID = 0; + int32 MapID = 0; + uint32 DifficultyID = 0; + int32 TimeRemaining = 0; + }; + + class CalendarRaidLockoutUpdated final : public ServerPacket + { + public: + CalendarRaidLockoutUpdated() : ServerPacket(SMSG_CALENDAR_RAID_LOCKOUT_UPDATED, 20) { } + + WorldPacket const* Write() override; + + WowTime ServerTime; + int32 MapID = 0; + uint32 DifficultyID = 0; + int32 NewTimeRemaining = 0; + int32 OldTimeRemaining = 0; + }; + + struct CalendarEventInitialInviteInfo + { + CalendarEventInitialInviteInfo(ObjectGuid inviteGuid, uint8 level) : InviteGuid(inviteGuid), Level(level) { } + + ObjectGuid InviteGuid; + uint8 Level = 100; + }; + + class CalendarEventInitialInvites final : public ServerPacket + { + public: + CalendarEventInitialInvites(bool guild) : ServerPacket(guild ? SMSG_CALENDAR_FILTER_GUILD : SMSG_CALENDAR_ARENA_TEAM, 17) { } + + WorldPacket const* Write() override; + + std::vector<CalendarEventInitialInviteInfo> Invites; + }; + + class CalendarInviteStatusAlert final : public ServerPacket + { + public: + CalendarInviteStatusAlert() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_STATUS_ALERT, 5) { } + + WorldPacket const* Write() override; + + uint64 EventID = 0; + uint32 Flags = 0; + WowTime Date; + uint8 Status = 0; + }; + + class CalendarInviteNotesAlert final : public ServerPacket + { + public: + CalendarInviteNotesAlert() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT, 9) { } + CalendarInviteNotesAlert(uint64 eventID, std::string const& notes) : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_NOTES_ALERT, 8 + notes.size()), EventID(eventID), Notes(notes) { } + + WorldPacket const* Write() override; + + uint64 EventID = 0; + std::string Notes; + }; + + class CalendarInviteNotes final : public ServerPacket + { + public: + CalendarInviteNotes() : ServerPacket(SMSG_CALENDAR_EVENT_INVITE_NOTES, 26) { } + + WorldPacket const* Write() override; + + ObjectGuid InviteGuid; + uint64 EventID = 0; + std::string Notes; + bool ClearPending = false; + }; + + class CalendarComplain final : public ClientPacket + { + public: + CalendarComplain(WorldPacket&& packet) : ClientPacket(CMSG_CALENDAR_COMPLAIN, std::move(packet)) { } + + void Read() override; + + ObjectGuid InvitedByGUID; + uint64 InviteID = 0; + uint64 EventID = 0; + }; + } +} + +#endif // CalendarPackets_h__ diff --git a/src/server/game/Server/Packets/GuildPackets.cpp b/src/server/game/Server/Packets/GuildPackets.cpp index 30cc4c941b9..b1965b454dc 100644 --- a/src/server/game/Server/Packets/GuildPackets.cpp +++ b/src/server/game/Server/Packets/GuildPackets.cpp @@ -50,7 +50,7 @@ void WorldPackets::Guild::GuildCreate::Read() WorldPacket const* WorldPackets::Guild::GuildInfoResponse::Write() { _worldPacket << GuildName; - _worldPacket.AppendPackedTime(CreateDate); + _worldPacket << CreateDate; _worldPacket << int32(NumMembers); _worldPacket << int32(NumAccounts); diff --git a/src/server/game/Server/Packets/GuildPackets.h b/src/server/game/Server/Packets/GuildPackets.h index 6815b936531..870af4439de 100644 --- a/src/server/game/Server/Packets/GuildPackets.h +++ b/src/server/game/Server/Packets/GuildPackets.h @@ -22,7 +22,7 @@ #include "Guild.h" #include "ObjectGuid.h" #include "PacketUtilities.h" -#include <boost/container/static_vector.hpp> +#include "WowTime.h" #include <array> namespace WorldPackets @@ -90,7 +90,7 @@ namespace WorldPackets WorldPacket const* Write() override; std::string GuildName; - time_t CreateDate = time_t(0); + WowTime CreateDate; int32 NumMembers = 0; int32 NumAccounts = 0; }; @@ -208,7 +208,7 @@ namespace WorldPackets WorldPacket const* Write() override; uint8 Type = 0; - boost::container::static_vector<std::string_view, 3> Params; + Array<std::string_view, 3> Params; ObjectGuid Guid; }; diff --git a/src/server/game/Server/Packets/MiscPackets.cpp b/src/server/game/Server/Packets/MiscPackets.cpp index 1ecdd99fbf8..17d667e7c77 100644 --- a/src/server/game/Server/Packets/MiscPackets.cpp +++ b/src/server/game/Server/Packets/MiscPackets.cpp @@ -77,7 +77,7 @@ WorldPacket const* WorldPackets::Misc::InvalidatePlayer::Write() WorldPacket const* WorldPackets::Misc::LoginSetTimeSpeed::Write() { - _worldPacket.AppendPackedTime(GameTime); + _worldPacket << GameTime; _worldPacket << float(NewSpeed); _worldPacket << uint32(GameTimeHolidayOffset); diff --git a/src/server/game/Server/Packets/MiscPackets.h b/src/server/game/Server/Packets/MiscPackets.h index 553fbba3dc1..e8ef57af674 100644 --- a/src/server/game/Server/Packets/MiscPackets.h +++ b/src/server/game/Server/Packets/MiscPackets.h @@ -23,6 +23,7 @@ #include "ObjectGuid.h" #include "Optional.h" #include "Weather.h" +#include "WowTime.h" #include <array> enum WeatherState : uint32; @@ -125,7 +126,7 @@ namespace WorldPackets WorldPacket const* Write() override; float NewSpeed = 0.0f; - uint32 GameTime = 0; + WowTime GameTime; int32 GameTimeHolidayOffset = 0; }; diff --git a/src/server/game/Server/WorldSession.cpp b/src/server/game/Server/WorldSession.cpp index 081c9693bdb..0ce690bd574 100644 --- a/src/server/game/Server/WorldSession.cpp +++ b/src/server/game/Server/WorldSession.cpp @@ -107,13 +107,14 @@ bool WorldSessionFilter::Process(WorldPacket* packet) } /// WorldSession constructor -WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter): +WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, + Minutes timezoneOffset, LocaleConstant locale, uint32 recruiter, bool isARecruiter): m_muteTime(mute_time), m_timeOutTime(0), AntiDOS(this), m_GUIDLow(0), _player(nullptr), - m_Socket(sock), + m_Socket(std::move(sock)), _security(sec), _accountId(id), _accountName(std::move(name)), @@ -126,6 +127,7 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS m_playerSave(false), m_sessionDbcLocale(sWorld->GetAvailableDbcLocale(locale)), m_sessionDbLocaleIndex(locale), + _timezoneOffset(timezoneOffset), m_latency(0), m_TutorialsChanged(TUTORIALS_FLAG_NONE), recruiterId(recruiter), @@ -144,9 +146,9 @@ WorldSession::WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldS { memset(m_Tutorials, 0, sizeof(m_Tutorials)); - if (sock) + if (m_Socket) { - m_Address = sock->GetRemoteIpAddress().to_string(); + m_Address = m_Socket->GetRemoteIpAddress().to_string(); ResetTimeOutTime(false); LoginDatabase.PExecute("UPDATE account SET online = 1 WHERE id = {};", GetAccountId()); // One-time query } diff --git a/src/server/game/Server/WorldSession.h b/src/server/game/Server/WorldSession.h index 10f198e1795..828aa415b1c 100644 --- a/src/server/game/Server/WorldSession.h +++ b/src/server/game/Server/WorldSession.h @@ -87,6 +87,27 @@ namespace WorldPackets class BuyBankSlot; } + namespace Calendar + { + class CalendarAddEvent; + class CalendarCopyEvent; + class CalendarInvite; + class CalendarModeratorStatusQuery; + class CalendarRSVP; + class CalendarEventSignUp; + class CalendarStatus; + class CalendarGetCalendar; + class CalendarGetEvent; + class CalendarGetNumPending; + class CalendarGuildFilter; + class CalendarArenaTeam; + class CalendarRemoveEvent; + class CalendarRemoveInvite; + class CalendarUpdateEvent; + class SetSavedInstanceExtend; + class CalendarComplain; + } + namespace Character { class LogoutCancel; @@ -400,7 +421,8 @@ struct PacketCounter class TC_GAME_API WorldSession { public: - WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, LocaleConstant locale, uint32 recruiter, bool isARecruiter); + WorldSession(uint32 id, std::string&& name, std::shared_ptr<WorldSocket> sock, AccountTypes sec, uint8 expansion, time_t mute_time, + Minutes timezoneOffset, LocaleConstant locale, uint32 recruiter, bool isARecruiter); ~WorldSession(); bool PlayerLoading() const { return m_playerLoading; } @@ -571,6 +593,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; } @@ -1079,26 +1104,27 @@ class TC_GAME_API WorldSession void HandleAcceptGrantLevel(WorldPacket& recvData); // Calendar - void HandleCalendarGetCalendar(WorldPacket& recvData); - void HandleCalendarGetEvent(WorldPacket& recvData); - void HandleCalendarGuildFilter(WorldPacket& recvData); - void HandleCalendarArenaTeam(WorldPacket& recvData); - void HandleCalendarAddEvent(WorldPacket& recvData); - void HandleCalendarUpdateEvent(WorldPacket& recvData); - void HandleCalendarRemoveEvent(WorldPacket& recvData); - void HandleCalendarCopyEvent(WorldPacket& recvData); - void HandleCalendarEventInvite(WorldPacket& recvData); - void HandleCalendarEventRsvp(WorldPacket& recvData); - void HandleCalendarEventRemoveInvite(WorldPacket& recvData); - void HandleCalendarEventStatus(WorldPacket& recvData); - void HandleCalendarEventModeratorStatus(WorldPacket& recvData); - void HandleCalendarComplain(WorldPacket& recvData); - void HandleCalendarGetNumPending(WorldPacket& recvData); - void HandleCalendarEventSignup(WorldPacket& recvData); - - void SendCalendarRaidLockout(InstanceSave const* save, bool add); + void HandleCalendarGetCalendar(WorldPackets::Calendar::CalendarGetCalendar& calendarGetCalendar); + void HandleCalendarGetEvent(WorldPackets::Calendar::CalendarGetEvent& calendarGetEvent); + void HandleCalendarGuildFilter(WorldPackets::Calendar::CalendarGuildFilter& calendarGuildFilter); + void HandleCalendarArenaTeam(WorldPackets::Calendar::CalendarArenaTeam& calendarArenaTeam); + void HandleCalendarAddEvent(WorldPackets::Calendar::CalendarAddEvent& calendarAddEvent); + void HandleCalendarUpdateEvent(WorldPackets::Calendar::CalendarUpdateEvent& calendarUpdateEvent); + void HandleCalendarRemoveEvent(WorldPackets::Calendar::CalendarRemoveEvent& calendarRemoveEvent); + void HandleCalendarCopyEvent(WorldPackets::Calendar::CalendarCopyEvent& calendarCopyEvent); + void HandleCalendarEventInvite(WorldPackets::Calendar::CalendarInvite& calendarEventInvite); + void HandleCalendarEventRsvp(WorldPackets::Calendar::CalendarRSVP& calendarRSVP); + void HandleCalendarEventRemoveInvite(WorldPackets::Calendar::CalendarRemoveInvite& calendarRemoveInvite); + void HandleCalendarEventStatus(WorldPackets::Calendar::CalendarStatus& calendarStatus); + void HandleCalendarEventModeratorStatus(WorldPackets::Calendar::CalendarModeratorStatusQuery& calendarModeratorStatus); + void HandleCalendarComplain(WorldPackets::Calendar::CalendarComplain& calendarComplain); + void HandleCalendarGetNumPending(WorldPackets::Calendar::CalendarGetNumPending& calendarGetNumPending); + void HandleCalendarEventSignup(WorldPackets::Calendar::CalendarEventSignUp& calendarEventSignUp); + + void SendCalendarRaidLockoutAdded(InstanceSave const* save); + void SendCalendarRaidLockoutRemoved(InstanceSave const* save); void SendCalendarRaidLockoutUpdated(InstanceSave const* save); - void HandleSetSavedInstanceExtend(WorldPacket& recvData); + void HandleSetSavedInstanceExtend(WorldPackets::Calendar::SetSavedInstanceExtend& setSavedInstanceExtend); void HandleSpellClick(WorldPacket& recvData); void HandleMirrorImageDataRequest(WorldPacket& recvData); @@ -1203,6 +1229,7 @@ class TC_GAME_API WorldSession bool m_playerSave; LocaleConstant m_sessionDbcLocale; LocaleConstant m_sessionDbLocaleIndex; + Minutes _timezoneOffset; std::atomic<uint32> m_latency; AccountData m_accountData[NUM_ACCOUNT_DATA_TYPES]; uint32 m_Tutorials[MAX_ACCOUNT_TUTORIAL_VALUES]; diff --git a/src/server/game/Server/WorldSocket.cpp b/src/server/game/Server/WorldSocket.cpp index 4603e619be5..6b89e04b6ee 100644 --- a/src/server/game/Server/WorldSocket.cpp +++ b/src/server/game/Server/WorldSocket.cpp @@ -254,15 +254,16 @@ struct AccountInfo LocaleConstant Locale; uint32 Recruiter; std::string OS; + Minutes TimezoneOffset; bool IsRectuiter; AccountTypes Security; bool IsBanned; - explicit AccountInfo(Field* fields) + explicit AccountInfo(Field const* fields) { - // 0 1 2 3 4 5 6 7 8 9 10 - // SELECT a.id, a.sessionkey, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, aa.gmLevel, - // 11 12 + // 0 1 2 3 4 5 6 7 8 9 10 11 + // SELECT a.id, a.sessionkey, a.last_ip, a.locked, a.lock_country, a.expansion, a.mutetime, a.locale, a.recruiter, a.os, a.timezone_offset, aa.SecurityLevel, + // 12 13 // ab.unbandate > UNIX_TIMESTAMP() OR ab.unbandate = ab.bandate, r.id // FROM account a // LEFT JOIN account_access aa ON a.id = aa.AccountID AND aa.RealmID IN (-1, ?) @@ -279,9 +280,10 @@ struct AccountInfo Locale = LocaleConstant(fields[7].GetUInt8()); Recruiter = fields[8].GetUInt32(); OS = fields[9].GetString(); - Security = AccountTypes(fields[10].GetUInt8()); - IsBanned = fields[11].GetUInt64() != 0; - IsRectuiter = fields[12].GetUInt32() != 0; + TimezoneOffset = Minutes(fields[10].GetInt16()); + Security = AccountTypes(fields[11].GetUInt8()); + IsBanned = fields[12].GetUInt64() != 0; + IsRectuiter = fields[13].GetUInt32() != 0; uint32 world_expansion = sWorld->getIntConfig(CONFIG_EXPANSION); if (Expansion > world_expansion) @@ -442,7 +444,10 @@ void WorldSocket::HandleAuthSession(WorldPacket& recvPacket) stmt->setInt32(0, int32(realm.Id.Realm)); stmt->setString(1, authSession->Account); - _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<AuthSession> authSession, PreparedQueryResult result) @@ -604,7 +609,7 @@ void WorldSocket::HandleAuthSessionCallback(std::shared_ptr<AuthSession> authSes _authed = true; _worldSession = new WorldSession(account.Id, std::move(authSession->Account), shared_from_this(), account.Security, - account.Expansion, mutetime, account.Locale, account.Recruiter, account.IsRectuiter); + account.Expansion, mutetime, account.TimezoneOffset, account.Locale, account.Recruiter, account.IsRectuiter); _worldSession->ReadAddonsInfo(authSession->AddonInfo); // Initialize Warden system only if it is enabled by config diff --git a/src/server/game/Time/GameTime.cpp b/src/server/game/Time/GameTime.cpp index 7742cabef20..733f381f796 100644 --- a/src/server/game/Time/GameTime.cpp +++ b/src/server/game/Time/GameTime.cpp @@ -17,6 +17,9 @@ #include "GameTime.h" #include "Timer.h" +#include "Timezone.h" +#include "Util.h" +#include "WowTime.h" namespace GameTime { @@ -28,6 +31,9 @@ namespace GameTime SystemTimePoint GameTimeSystemPoint = SystemTimePoint ::min(); TimePoint GameTimeSteadyPoint = TimePoint::min(); + WowTime UtcWow; + WowTime Wow; + time_t GetStartTime() { return StartTime; @@ -58,11 +64,23 @@ namespace GameTime return uint32(GameTime - StartTime); } + WowTime const* GetUtcWowTime() + { + return &UtcWow; + } + + WowTime const* GetWowTime() + { + return &Wow; + } + void UpdateGameTimers() { GameTime = time(nullptr); GameMSTime = getMSTime(); GameTimeSystemPoint = std::chrono::system_clock::now(); GameTimeSteadyPoint = std::chrono::steady_clock::now(); + 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 838984be72a..3ff411e867a 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 @@ -41,6 +43,10 @@ namespace GameTime /// Uptime (in secs) TC_GAME_API uint32 GetUptime(); + 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 aff903f4846..2a784027dc3 100644 --- a/src/server/shared/Packets/ByteBuffer.cpp +++ b/src/server/shared/Packets/ByteBuffer.cpp @@ -24,7 +24,6 @@ #include <utf8.h> #include <sstream> #include <cmath> -#include <ctime> ByteBuffer::ByteBuffer(MessageBuffer&& buffer) : _rpos(0), _wpos(0), _storage(buffer.Move()) { @@ -90,21 +89,6 @@ std::string ByteBuffer::ReadCString(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()); @@ -130,13 +114,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 aa387d0842b..e19e89ede22 100644 --- a/src/server/shared/Packets/ByteBuffer.h +++ b/src/server/shared/Packets/ByteBuffer.h @@ -392,14 +392,6 @@ class TC_SHARED_API ByteBuffer std::string ReadCString(bool requireValidUtf8 = true); - uint32 ReadPackedTime(); - - ByteBuffer& ReadPackedTime(uint32& time) - { - time = ReadPackedTime(); - return *this; - } - uint8* contents() { if (_storage.empty()) @@ -488,8 +480,6 @@ class TC_SHARED_API ByteBuffer append(packGUID, size); } - void AppendPackedTime(time_t time); - void put(size_t pos, const uint8 *src, size_t cnt); void print_storage() const; diff --git a/src/server/shared/Realm/RealmList.h b/src/server/shared/Realm/RealmList.h index b5ef9c33b7b..056472533e2 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> |