From 0f4130704aa18a3da81bf48a20fe80871eeb5640 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Wed, 21 Feb 2024 16:36:19 -0500 Subject: [PATCH] Core/Calendar: Implement different timezone support for ingame calendar Port From (https://github.com/TrinityCore/TrinityCore/commit/b888b1b09f71a8b8b4a9d45c804a1f164fb65ac3) --- .../Networking/Services/Authentication.cs | 16 ++ Source/BNetServer/Server.cs | 3 - Source/Framework/{Util => Time}/Time.cs | 2 +- Source/Framework/Time/Timezone.cs | 78 ++++++ Source/Framework/Util/Extensions.cs | 11 + .../Game/Achievements/AchievementManager.cs | 194 +++++++++------ Source/Game/Achievements/CriteriaHandler.cs | 9 +- Source/Game/AuctionHouse/AuctionManager.cs | 8 +- Source/Game/Calendar/CalendarManager.cs | 202 +++++++++------ Source/Game/Conditions/ConditionManager.cs | 14 +- Source/Game/Entities/Object/WorldObject.cs | 6 +- Source/Game/Entities/Player/Player.cs | 12 +- Source/Game/Guilds/Guild.cs | 62 +++-- Source/Game/Handlers/AuthenticationHandler.cs | 13 +- Source/Game/Handlers/CalendarHandler.cs | 32 ++- Source/Game/Maps/GridNotifiers.cs | 19 +- .../Networking/Packets/AchievementPackets.cs | 28 +-- .../Networking/Packets/CalendarPackets.cs | 82 +++--- .../Game/Networking/Packets/GuildPackets.cs | 8 +- Source/Game/Networking/Packets/MiscPackets.cs | 8 +- .../Quest/QuestObjectiveCriteriaManager.cs | 12 +- Source/Game/Scenarios/Scenario.cs | 72 +++--- Source/Game/Time/GameTime.cs | 22 +- Source/Game/Time/Updatetime.cs | 5 +- Source/Game/Time/WowTime.cs | 235 ++++++++++++++++++ 25 files changed, 831 insertions(+), 322 deletions(-) rename Source/Framework/{Util => Time}/Time.cs (99%) create mode 100644 Source/Framework/Time/Timezone.cs create mode 100644 Source/Game/Time/WowTime.cs diff --git a/Source/BNetServer/Networking/Services/Authentication.cs b/Source/BNetServer/Networking/Services/Authentication.cs index 0fdd44b07..f172118f1 100644 --- a/Source/BNetServer/Networking/Services/Authentication.cs +++ b/Source/BNetServer/Networking/Services/Authentication.cs @@ -4,11 +4,13 @@ using Bgs.Protocol; using Bgs.Protocol.Authentication.V1; using Bgs.Protocol.Challenge.V1; +using Framework; using Framework.Constants; using Framework.Database; using Framework.Realm; using Google.Protobuf; using System; +using System.Text.Json; namespace BNetServer.Networking { @@ -39,6 +41,20 @@ namespace BNetServer.Networking os = logonRequest.Platform; build = (uint)logonRequest.ApplicationVersion; + _timezoneOffset = TimeSpan.Zero; + if (logonRequest.HasDeviceId) + { + var doc = JsonSerializer.Deserialize(logonRequest.DeviceId); + if (doc != null) + { + var itr = doc.RootElement.GetProperty("UTCO"); + { + if (itr.TryGetUInt32(out uint value)) + _timezoneOffset = Timezone.GetOffsetByHash(value); + } + } + } + ChallengeExternalRequest externalChallenge = new(); externalChallenge.PayloadType = "web_auth_url"; externalChallenge.Payload = ByteString.CopyFromUtf8($"https://{Global.LoginService.GetHostnameForClient(GetRemoteIpAddress())}:{Global.LoginService.GetPort()}/bnetserver/login/"); diff --git a/Source/BNetServer/Server.cs b/Source/BNetServer/Server.cs index 730cd2bf2..a7300826c 100644 --- a/Source/BNetServer/Server.cs +++ b/Source/BNetServer/Server.cs @@ -1,11 +1,8 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. -using BNetServer.Networking; using Framework.Configuration; -using Framework.Cryptography; using Framework.Database; -using Framework.Networking; using System; using System.Globalization; using System.Timers; diff --git a/Source/Framework/Util/Time.cs b/Source/Framework/Time/Time.cs similarity index 99% rename from Source/Framework/Util/Time.cs rename to Source/Framework/Time/Time.cs index 9fc871226..9658c0961 100644 --- a/Source/Framework/Util/Time.cs +++ b/Source/Framework/Time/Time.cs @@ -93,7 +93,7 @@ public static class Time public static DateTime UnixTimeToDateTime(long unixTime) { - return DateTimeOffset.FromUnixTimeSeconds(unixTime).LocalDateTime; + return DateTimeOffset.FromUnixTimeSeconds(unixTime).DateTime; } public static long DateTimeToUnixTime(DateTime dateTime) diff --git a/Source/Framework/Time/Timezone.cs b/Source/Framework/Time/Timezone.cs new file mode 100644 index 000000000..8a3b2dd91 --- /dev/null +++ b/Source/Framework/Time/Timezone.cs @@ -0,0 +1,78 @@ +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Framework +{ + public class Timezone + { + static Dictionary _timezoneOffsetsByHash = InitTimezoneHashDb(); + + static Dictionary InitTimezoneHashDb() + { + // Generate our hash db to match values sent in client authentication packets + Dictionary hashToOffset = new(); + foreach (var sysInfo in TimeZoneInfo.GetSystemTimeZones()) + { + TimeSpan offsetMinutes = sysInfo.BaseUtcOffset; + hashToOffset.TryAdd(offsetMinutes.TotalMinutes.ToString().HashFnv1a(), offsetMinutes); + } + + return hashToOffset; + } + + static (TimeSpan, string)[] _clientSupportedTimezones = + { + (TimeSpan.FromMinutes(-480), "America/Los_Angeles"), + ( TimeSpan.FromMinutes(-420), "America/Denver" ), + ( TimeSpan.FromMinutes(-360), "America/Chicago" ), + ( TimeSpan.FromMinutes(-300), "America/New_York" ), + ( TimeSpan.FromMinutes(-180), "America/Sao_Paulo" ), + ( TimeSpan.FromMinutes(0), "Etc/UTC" ), + ( TimeSpan.FromMinutes(60), "Europe/Paris" ), + ( TimeSpan.FromMinutes(480), "Asia/Shanghai" ), + ( TimeSpan.FromMinutes(480), "Asia/Taipei" ), + ( TimeSpan.FromMinutes(540), "Asia/Seoul" ), + ( TimeSpan.FromMinutes(600), "Australia/Melbourne" ), + }; + + public static TimeSpan GetOffsetByHash(uint hash) + { + if (_timezoneOffsetsByHash.TryGetValue(hash, out var offset)) + return offset; + + return TimeSpan.Zero; + } + + public static TimeSpan GetSystemZoneOffsetAt(DateTime date) + { + return TimeZoneInfo.Local.GetUtcOffset(date); + } + + public static TimeSpan GetSystemZoneOffset() + { + return DateTimeOffset.Now.Offset; + } + + public static string GetSystemZoneName() + { + return TimeZoneInfo.Local.StandardName; + } + + public static string FindClosestClientSupportedTimezone(string currentTimezone, TimeSpan currentTimezoneOffset) + { + // try exact match + var pair = _clientSupportedTimezones.FirstOrDefault(tz => tz.Item2 == currentTimezone); + if (!pair.Item2.IsEmpty()) + return pair.Item2; + + // try closest offset + pair = _clientSupportedTimezones.MinBy(left => left.Item1 - currentTimezoneOffset); + + return pair.Item2; + } + } +} diff --git a/Source/Framework/Util/Extensions.cs b/Source/Framework/Util/Extensions.cs index 311752735..84776a600 100644 --- a/Source/Framework/Util/Extensions.cs +++ b/Source/Framework/Util/Extensions.cs @@ -422,6 +422,17 @@ namespace System return -1; } + + public static uint HashFnv1a(this string data) + { + uint hash = 0x811C9DC5u; + foreach (char c in data) + { + hash ^= c; + hash *= 0x1000193u; + } + return hash; + } #endregion #region BinaryReader diff --git a/Source/Game/Achievements/AchievementManager.cs b/Source/Game/Achievements/AchievementManager.cs index 78f65e7f6..a1c1636f0 100644 --- a/Source/Game/Achievements/AchievementManager.cs +++ b/Source/Game/Achievements/AchievementManager.cs @@ -49,7 +49,7 @@ namespace Game.Achievements { return _completedAchievements.Keys; } - + public override bool CanUpdateCriteriaTree(Criteria criteria, CriteriaTree tree, Player referencePlayer) { AchievementRecord achievement = tree.Achievement; @@ -178,9 +178,9 @@ namespace Game.Achievements public virtual void CompletedAchievement(AchievementRecord entry, Player referencePlayer) { } - public Func, AchievementRecord> VisibleAchievementCheck = value => + public Func VisibleAchievementCheck = id => { - AchievementRecord achievement = CliDB.AchievementStorage.LookupByKey(value.Key); + AchievementRecord achievement = CliDB.AchievementStorage.LookupByKey(id); if (achievement != null && !achievement.Flags.HasAnyFlag(AchievementFlags.Hidden)) return achievement; return null; @@ -358,33 +358,35 @@ namespace Game.Achievements AllAccountCriteria allAccountCriteria = new(); AllAchievementData achievementData = new(); - foreach (var pair in _completedAchievements) + foreach (var (id, completedAchievement) in _completedAchievements) { - AchievementRecord achievement = VisibleAchievementCheck(pair); + AchievementRecord achievement = VisibleAchievementCheck(id); if (achievement == null) continue; EarnedAchievement earned = new(); - earned.Id = pair.Key; - earned.Date = pair.Value.Date; + earned.Id = id; + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.Date); if (!achievement.Flags.HasAnyFlag(AchievementFlags.Account)) { earned.Owner = _owner.GetGUID(); earned.VirtualRealmAddress = earned.NativeRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); } + achievementData.Data.Earned.Add(earned); } - foreach (var pair in _criteriaProgress) + foreach (var (id, criteriaProgres) in _criteriaProgress) { - Criteria criteria = Global.CriteriaMgr.GetCriteria(pair.Key); + Criteria criteria = Global.CriteriaMgr.GetCriteria(id); CriteriaProgressPkt progress = new(); - progress.Id = pair.Key; - progress.Quantity = pair.Value.Counter; - progress.Player = pair.Value.PlayerGUID; + progress.Id = id; + progress.Quantity = criteriaProgres.Counter; + progress.Player = criteriaProgres.PlayerGUID; progress.Flags = 0; - progress.Date = pair.Value.Date; + progress.Date.SetUtcTimeFromUnixTime(criteriaProgres.Date); + progress.Date += _owner.GetSession().GetTimezoneOffset(); progress.TimeFromStart = 0; progress.TimeFromCreate = 0; achievementData.Data.Progress.Add(progress); @@ -392,11 +394,12 @@ namespace Game.Achievements if (criteria.FlagsCu.HasAnyFlag(CriteriaFlagsCu.Account)) { CriteriaProgressPkt accountProgress = new(); - accountProgress.Id = pair.Key; - accountProgress.Quantity = pair.Value.Counter; + accountProgress.Id = id; + accountProgress.Quantity = criteriaProgres.Counter; accountProgress.Player = _owner.GetSession().GetBattlenetAccountGUID(); accountProgress.Flags = 0; - accountProgress.Date = pair.Value.Date; + accountProgress.Date.SetUtcTimeFromUnixTime(criteriaProgres.Date); + accountProgress.Date += _owner.GetSession().GetTimezoneOffset(); accountProgress.TimeFromStart = 0; accountProgress.TimeFromCreate = 0; allAccountCriteria.Progress.Add(accountProgress); @@ -414,31 +417,34 @@ namespace Game.Achievements RespondInspectAchievements inspectedAchievements = new(); inspectedAchievements.Player = _owner.GetGUID(); - foreach (var pair in _completedAchievements) + foreach (var (id, completedAchievement) in _completedAchievements) { - AchievementRecord achievement = VisibleAchievementCheck(pair); + AchievementRecord achievement = VisibleAchievementCheck(id); if (achievement == null) continue; EarnedAchievement earned = new(); - earned.Id = pair.Key; - earned.Date = pair.Value.Date; + earned.Id = id; + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.Date); + earned.Date += receiver.GetSession().GetTimezoneOffset(); if (!achievement.Flags.HasAnyFlag(AchievementFlags.Account)) { earned.Owner = _owner.GetGUID(); earned.VirtualRealmAddress = earned.NativeRealmAddress = Global.WorldMgr.GetVirtualRealmAddress(); } + inspectedAchievements.Data.Earned.Add(earned); } - foreach (var pair in _criteriaProgress) + foreach (var (id, criteriaProgres) in _criteriaProgress) { CriteriaProgressPkt progress = new(); - progress.Id = pair.Key; - progress.Quantity = pair.Value.Counter; - progress.Player = pair.Value.PlayerGUID; + progress.Id = id; + progress.Quantity = criteriaProgres.Counter; + progress.Player = criteriaProgres.PlayerGUID; progress.Flags = 0; - progress.Date = pair.Value.Date; + progress.Date.SetUtcTimeFromUnixTime(criteriaProgres.Date); + progress.Date += receiver.GetSession().GetTimezoneOffset(); progress.TimeFromStart = 0; progress.TimeFromCreate = 0; inspectedAchievements.Data.Progress.Add(progress); @@ -571,7 +577,8 @@ namespace Game.Achievements if (criteria.Entry.StartTimer != 0) criteriaUpdate.Progress.Flags = timedCompleted ? 1 : 0u; // 1 is for keeping the counter at 0 in client - criteriaUpdate.Progress.Date = progress.Date; + criteriaUpdate.Progress.Date.SetUtcTimeFromUnixTime(progress.Date); + criteriaUpdate.Progress.Date += _owner.GetSession().GetTimezoneOffset(); criteriaUpdate.Progress.TimeFromStart = (uint)timeElapsed.TotalSeconds; criteriaUpdate.Progress.TimeFromCreate = 0; SendPacket(criteriaUpdate); @@ -588,7 +595,8 @@ namespace Game.Achievements if (criteria.Entry.StartTimer != 0) criteriaUpdate.Flags = timedCompleted ? 1 : 0u; // 1 is for keeping the counter at 0 in client - criteriaUpdate.CurrentTime = progress.Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(progress.Date); + criteriaUpdate.CurrentTime += _owner.GetSession().GetTimezoneOffset(); criteriaUpdate.ElapsedTime = (uint)timeElapsed.TotalSeconds; criteriaUpdate.CreationTime = 0; @@ -640,17 +648,26 @@ namespace Game.Achievements } } - AchievementEarned achievementEarned = new(); - achievementEarned.Sender = _owner.GetGUID(); - achievementEarned.Earner = _owner.GetGUID(); - achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress(); - achievementEarned.AchievementID = achievement.Id; - achievementEarned.Time = GameTime.GetGameTime(); + var achievementEarnedBuilder = (Player receiver) => + { + AchievementEarned achievementEarned = new(); + achievementEarned.Sender = _owner.GetGUID(); + achievementEarned.Earner = _owner.GetGUID(); + achievementEarned.EarnerNativeRealm = achievementEarned.EarnerVirtualRealm = Global.WorldMgr.GetVirtualRealmAddress(); + achievementEarned.AchievementID = achievement.Id; + achievementEarned.Time = GameTime.GetUtcWowTime(); + achievementEarned.Time += receiver.GetSession().GetTimezoneOffset(); + receiver.SendPacket(achievementEarned); + }; if (!achievement.Flags.HasAnyFlag(AchievementFlags.TrackingFlag)) - _owner.SendMessageToSetInRange(achievementEarned, WorldConfig.GetFloatValue(WorldCfg.ListenRangeSay), true); + { + float dist = WorldConfig.GetFloatValue(WorldCfg.ListenRangeSay); + MessageDistDeliverer notifier = new(_owner, achievementEarnedBuilder, dist); + Cell.VisitWorldObjects(_owner, notifier, dist); + } else - _owner.SendPacket(achievementEarned); + achievementEarnedBuilder(_owner); } public override void SendPacket(ServerPacket data) @@ -683,13 +700,17 @@ namespace Game.Achievements base.Reset(); ObjectGuid guid = _owner.GetGUID(); - foreach (var iter in _completedAchievements) + foreach (var (id, _) in _completedAchievements) { - GuildAchievementDeleted guildAchievementDeleted = new(); - guildAchievementDeleted.AchievementID = iter.Key; - guildAchievementDeleted.GuildGUID = guid; - guildAchievementDeleted.TimeDeleted = GameTime.GetGameTime(); - SendPacket(guildAchievementDeleted); + _owner.BroadcastWorker(receiver => + { + GuildAchievementDeleted guildAchievementDeleted = new(); + guildAchievementDeleted.AchievementID = id; + guildAchievementDeleted.GuildGUID = guid; + guildAchievementDeleted.TimeDeleted = GameTime.GetUtcWowTime(); + guildAchievementDeleted.TimeDeleted += receiver.GetSession().GetTimezoneOffset(); + receiver.SendPacket(guildAchievementDeleted); + }); } _achievementPoints = 0; @@ -831,15 +852,16 @@ namespace Game.Achievements { AllGuildAchievements allGuildAchievements = new(); - foreach (var pair in _completedAchievements) + foreach (var (id, completedAchievement) in _completedAchievements) { - AchievementRecord achievement = VisibleAchievementCheck(pair); + AchievementRecord achievement = VisibleAchievementCheck(id); if (achievement == null) continue; EarnedAchievement earned = new(); - earned.Id = pair.Key; - earned.Date = pair.Value.Date; + earned.Id = id; + earned.Date.SetUtcTimeFromUnixTime(completedAchievement.Date); + earned.Date += receiver.GetSession().GetTimezoneOffset(); allGuildAchievements.Earned.Add(earned); } @@ -856,25 +878,26 @@ namespace Game.Achievements if (tree != null) { CriteriaManager.WalkCriteriaTree(tree, node => - { - if (node.Criteria != null) - { - var progress = _criteriaProgress.LookupByKey(node.Criteria.Id); - if (progress != null) { - GuildCriteriaProgress guildCriteriaProgress = new(); - guildCriteriaProgress.CriteriaID = node.Criteria.Id; - guildCriteriaProgress.DateCreated = 0; - guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress.Date; - guildCriteriaProgress.Quantity = progress.Counter; - guildCriteriaProgress.PlayerGUID = progress.PlayerGUID; - guildCriteriaProgress.Flags = 0; + if (node.Criteria != null) + { + var progress = _criteriaProgress.LookupByKey(node.Criteria.Id); + if (progress != null) + { + GuildCriteriaProgress guildCriteriaProgress = new(); + guildCriteriaProgress.CriteriaID = node.Criteria.Id; + guildCriteriaProgress.DateCreated = 0; + guildCriteriaProgress.DateStarted = 0; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress.Date); + guildCriteriaProgress.DateUpdated += receiver.GetSession().GetTimezoneOffset(); + guildCriteriaProgress.Quantity = progress.Counter; + guildCriteriaProgress.PlayerGUID = progress.PlayerGUID; + guildCriteriaProgress.Flags = 0; - guildCriteriaUpdate.Progress.Add(guildCriteriaProgress); - } - } - }); + guildCriteriaUpdate.Progress.Add(guildCriteriaProgress); + } + } + }); } } @@ -895,7 +918,8 @@ namespace Game.Achievements guildCriteriaProgress.CriteriaID = criteriaId; guildCriteriaProgress.DateCreated = 0; guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress.Date; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress.Date); + guildCriteriaProgress.DateUpdated += receiver.GetSession().GetTimezoneOffset(); guildCriteriaProgress.Quantity = progress.Counter; guildCriteriaProgress.PlayerGUID = progress.PlayerGUID; guildCriteriaProgress.Flags = 0; @@ -975,20 +999,22 @@ namespace Game.Achievements public override void SendCriteriaUpdate(Criteria entry, CriteriaProgress progress, TimeSpan timeElapsed, bool timedCompleted) { - GuildCriteriaUpdate guildCriteriaUpdate = new(); + foreach (Player member in _owner.GetMembersTrackingCriteria(entry.Id)) + { + GuildCriteriaUpdate guildCriteriaUpdate = new(); + GuildCriteriaProgress guildCriteriaProgress = new(); + guildCriteriaProgress.CriteriaID = entry.Id; + guildCriteriaProgress.DateCreated = 0; + guildCriteriaProgress.DateStarted = 0; + guildCriteriaProgress.DateUpdated.SetUtcTimeFromUnixTime(progress.Date); + guildCriteriaProgress.DateUpdated += member.GetSession().GetTimezoneOffset(); + guildCriteriaProgress.Quantity = progress.Counter; + guildCriteriaProgress.PlayerGUID = progress.PlayerGUID; + guildCriteriaProgress.Flags = 0; + guildCriteriaUpdate.Progress.Add(guildCriteriaProgress); - GuildCriteriaProgress guildCriteriaProgress = new(); - guildCriteriaProgress.CriteriaID = entry.Id; - guildCriteriaProgress.DateCreated = 0; - guildCriteriaProgress.DateStarted = 0; - guildCriteriaProgress.DateUpdated = progress.Date; - guildCriteriaProgress.Quantity = progress.Counter; - guildCriteriaProgress.PlayerGUID = progress.PlayerGUID; - guildCriteriaProgress.Flags = 0; - - guildCriteriaUpdate.Progress.Add(guildCriteriaProgress); - - _owner.BroadcastPacketIfTrackingAchievement(guildCriteriaUpdate, entry.Id); + member.SendPacket(guildCriteriaUpdate); + } } public override void SendCriteriaProgressRemoved(uint criteriaId) @@ -1012,11 +1038,17 @@ namespace Game.Achievements Global.WorldMgr.SendGlobalMessage(serverFirstAchievement); } - GuildAchievementEarned guildAchievementEarned = new(); - guildAchievementEarned.AchievementID = achievement.Id; - guildAchievementEarned.GuildGUID = _owner.GetGUID(); - guildAchievementEarned.TimeEarned = GameTime.GetGameTime(); - SendPacket(guildAchievementEarned); + var guildAchievementEarnedBuilder = (Player receiver) => + { + GuildAchievementEarned guildAchievementEarned = new(); + guildAchievementEarned.AchievementID = achievement.Id; + guildAchievementEarned.GuildGUID = _owner.GetGUID(); + guildAchievementEarned.TimeEarned = GameTime.GetUtcWowTime(); + guildAchievementEarned.TimeEarned += receiver.GetSession().GetTimezoneOffset(); + receiver.SendPacket(guildAchievementEarned); + }; + + _owner.BroadcastWorker(guildAchievementEarnedBuilder); } public override void SendPacket(ServerPacket data) diff --git a/Source/Game/Achievements/CriteriaHandler.cs b/Source/Game/Achievements/CriteriaHandler.cs index dafd9e745..1a594d9ba 100644 --- a/Source/Game/Achievements/CriteriaHandler.cs +++ b/Source/Game/Achievements/CriteriaHandler.cs @@ -1790,9 +1790,12 @@ namespace Game.Achievements break; case ModifierTreeType.TimeBetween: // 109 { - long from = Time.GetUnixTimeFromPackedTime(reqValue); - long to = Time.GetUnixTimeFromPackedTime((uint)secondaryAsset); - if (GameTime.GetGameTime() < from || GameTime.GetGameTime() > to) + WowTime from = new(); + from.SetPackedTime(reqValue); + WowTime to = new(); + to.SetPackedTime((uint)secondaryAsset); + + if (!GameTime.GetWowTime().IsInRange(from, to)) return false; break; } diff --git a/Source/Game/AuctionHouse/AuctionManager.cs b/Source/Game/AuctionHouse/AuctionManager.cs index b1d145ffb..4faf49799 100644 --- a/Source/Game/AuctionHouse/AuctionManager.cs +++ b/Source/Game/AuctionHouse/AuctionManager.cs @@ -1547,13 +1547,13 @@ namespace Game // owner exist (online or offline) if ((owner != null || Global.CharacterCacheStorage.HasCharacterCacheEntry(auction.Owner)))// && !sAuctionBotConfig.IsBotChar(auction.Owner)) { - ByteBuffer tempBuffer = new(); - tempBuffer.WritePackedTime(GameTime.GetGameTime() + WorldConfig.GetIntValue(WorldCfg.MailDeliveryDelay)); - uint eta = tempBuffer.ReadUInt32(); + WowTime eta = GameTime.GetUtcWowTime(); + eta += TimeSpan.FromSeconds(WorldConfig.GetIntValue(WorldCfg.MailDeliveryDelay)); + eta += owner.GetSession().GetTimezoneOffset(); new MailDraft(Global.AuctionHouseMgr.BuildItemAuctionMailSubject(AuctionMailType.Invoice, auction), Global.AuctionHouseMgr.BuildAuctionInvoiceMailBody(auction.Bidder, auction.BidAmount, auction.BuyoutOrUnitPrice, (uint)auction.Deposit, - CalculateAuctionHouseCut(auction.BidAmount), WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay), eta)) + CalculateAuctionHouseCut(auction.BidAmount), WorldConfig.GetUIntValue(WorldCfg.MailDeliveryDelay), eta.GetPackedTime())) .SendMailTo(trans, new MailReceiver(owner, auction.Owner), new MailSender(this), MailCheckMask.Copied); } } diff --git a/Source/Game/Calendar/CalendarManager.cs b/Source/Game/Calendar/CalendarManager.cs index 8ae979a5f..1ffc17dd7 100644 --- a/Source/Game/Calendar/CalendarManager.cs +++ b/Source/Game/Calendar/CalendarManager.cs @@ -19,7 +19,7 @@ namespace Game CalendarManager() { _events = new List(); - _invites = new MultiMap(); + _invites = new MultiMap(); } public void LoadFromDB() @@ -147,7 +147,6 @@ namespace Game SQLTransaction trans = new(); PreparedStatement stmt; - MailDraft mail = new(calendarEvent.BuildCalendarMailSubject(remover), calendarEvent.BuildCalendarMailBody()); var eventInvites = _invites[calendarEvent.EventId]; for (int i = 0; i < eventInvites.Count; ++i) @@ -160,7 +159,10 @@ namespace Game // guild events only? check invite status here? // When an event is deleted, all invited (accepted/declined? - verify) guildies are notified via in-game mail. (wowwiki) if (!remover.IsEmpty() && invite.InviteeGuid != remover) + { + MailDraft mail = new(calendarEvent.BuildCalendarMailSubject(remover), calendarEvent.BuildCalendarMailBody(Global.ObjAccessor.FindConnectedPlayer(invite.InviteeGuid))); mail.SendMailTo(trans, new MailReceiver(invite.InviteeGuid.GetCounter()), new MailSender(calendarEvent), MailCheckMask.Copied); + } } _invites.Remove(calendarEvent.EventId); @@ -361,7 +363,7 @@ namespace Game return result; } - + public List GetPlayerEvents(ObjectGuid guid) { List events = new(); @@ -436,68 +438,100 @@ namespace Game uint level = player != null ? player.GetLevel() : Global.CharacterCacheStorage.GetCharacterLevelByGuid(invitee); - CalendarInviteAdded packet = new(); - packet.EventID = calendarEvent != null ? calendarEvent.EventId : 0; - packet.InviteGuid = invitee; - packet.InviteID = calendarEvent != null ? invite.InviteId : 0; - packet.Level = (byte)level; - packet.ResponseTime = invite.ResponseTime; - packet.Status = invite.Status; - packet.Type = (byte)(calendarEvent != null ? calendarEvent.IsGuildEvent() ? 1 : 0 : 0); // Correct ? - packet.ClearPending = calendarEvent == null || !calendarEvent.IsGuildEvent(); // Correct ? + var packetBuilder = (Player receiver) => + { + CalendarInviteAdded packet = new(); + packet.EventID = calendarEvent != null ? calendarEvent.EventId : 0; + packet.InviteGuid = invitee; + packet.InviteID = calendarEvent != null ? invite.InviteId : 0; + packet.Level = (byte)level; + packet.ResponseTime.SetUtcTimeFromUnixTime(invite.ResponseTime); + packet.ResponseTime += receiver.GetSession().GetTimezoneOffset(); + packet.Status = invite.Status; + packet.Type = (byte)(calendarEvent != null ? calendarEvent.IsGuildEvent() ? 1 : 0 : 0); // Correct ? + packet.ClearPending = calendarEvent != null ? !calendarEvent.IsGuildEvent() : true; // Correct ? + + receiver.SendPacket(packet); + }; if (calendarEvent == null) // Pre-invite { player = Global.ObjAccessor.FindPlayer(invite.SenderGuid); if (player != null) - player.SendPacket(packet); + packetBuilder(player); } else { if (calendarEvent.OwnerGuid != invite.InviteeGuid) // correct? - SendPacketToAllEventRelatives(packet, calendarEvent); + foreach (Player receiver in GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } } public void SendCalendarEventUpdateAlert(CalendarEvent calendarEvent, long originalDate) { - CalendarEventUpdatedAlert packet = new(); - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.Date; - packet.Description = calendarEvent.Description; - packet.EventID = calendarEvent.EventId; - packet.EventName = calendarEvent.Title; - packet.EventType = calendarEvent.EventType; - packet.Flags = calendarEvent.Flags; - packet.LockDate = calendarEvent.LockDate; // Always 0 ? - packet.OriginalDate = originalDate; - packet.TextureID = calendarEvent.TextureId; + var packetBuilder = (Player receiver) => + { + CalendarEventUpdatedAlert packet = new(); + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += receiver.GetSession().GetTimezoneOffset(); + packet.Description = calendarEvent.Description; + packet.EventID = calendarEvent.EventId; + packet.EventName = calendarEvent.Title; + packet.EventType = calendarEvent.EventType; + packet.Flags = calendarEvent.Flags; + packet.LockDate.SetUtcTimeFromUnixTime(calendarEvent.LockDate); // Always 0 ? + if (calendarEvent.LockDate != 0) + packet.LockDate += receiver.GetSession().GetTimezoneOffset(); + packet.OriginalDate.SetUtcTimeFromUnixTime(originalDate); + packet.OriginalDate += receiver.GetSession().GetTimezoneOffset(); + packet.TextureID = calendarEvent.TextureId; - SendPacketToAllEventRelatives(packet, calendarEvent); + receiver.SendPacket(packet); + }; + + foreach (Player receiver in GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } public void SendCalendarEventStatus(CalendarEvent calendarEvent, CalendarInvite invite) { - CalendarInviteStatusPacket packet = new(); - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.Date; - packet.EventID = calendarEvent.EventId; - packet.Flags = calendarEvent.Flags; - packet.InviteGuid = invite.InviteeGuid; - packet.ResponseTime = invite.ResponseTime; - packet.Status = invite.Status; + var packetBuilder = (Player receiver) => + { + CalendarInviteStatusPacket packet = new(); + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += receiver.GetSession().GetTimezoneOffset(); + packet.EventID = calendarEvent.EventId; + packet.Flags = calendarEvent.Flags; + packet.InviteGuid = invite.InviteeGuid; + packet.ResponseTime.SetUtcTimeFromUnixTime(invite.ResponseTime); + packet.ResponseTime += receiver.GetSession().GetTimezoneOffset(); + packet.Status = invite.Status; - SendPacketToAllEventRelatives(packet, calendarEvent); + receiver.SendPacket(packet); + }; + + foreach (Player receiver in GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } void SendCalendarEventRemovedAlert(CalendarEvent calendarEvent) { - CalendarEventRemovedAlert packet = new(); - packet.ClearPending = true; // FIXME - packet.Date = calendarEvent.Date; - packet.EventID = calendarEvent.EventId; + var packetBuilder = (Player receiver) => + { + CalendarEventRemovedAlert packet = new(); + packet.ClearPending = true; // FIXME + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += receiver.GetSession().GetTimezoneOffset(); + packet.EventID = calendarEvent.EventId; - SendPacketToAllEventRelatives(packet, calendarEvent); + receiver.SendPacket(packet); + }; + + foreach (Player receiver in GetAllEventRelatives(calendarEvent)) + packetBuilder(receiver); } void SendCalendarEventInviteRemove(CalendarEvent calendarEvent, CalendarInvite invite, uint flags) @@ -524,33 +558,37 @@ namespace Game void SendCalendarEventInviteAlert(CalendarEvent calendarEvent, CalendarInvite invite) { - CalendarInviteAlert packet = new(); - packet.Date = calendarEvent.Date; - packet.EventID = calendarEvent.EventId; - packet.EventName = calendarEvent.Title; - packet.EventType = calendarEvent.EventType; - packet.Flags = calendarEvent.Flags; - packet.InviteID = invite.InviteId; - packet.InvitedByGuid = invite.SenderGuid; - packet.ModeratorStatus = invite.Rank; - packet.OwnerGuid = calendarEvent.OwnerGuid; - packet.Status = invite.Status; - packet.TextureID = calendarEvent.TextureId; + var packetBuilder = (Player receiver) => + { + CalendarInviteAlert packet = new(); + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += receiver.GetSession().GetTimezoneOffset(); + packet.EventID = calendarEvent.EventId; + packet.EventName = calendarEvent.Title; + packet.EventType = calendarEvent.EventType; + packet.Flags = calendarEvent.Flags; + packet.InviteID = invite.InviteId; + packet.InvitedByGuid = invite.SenderGuid; + packet.ModeratorStatus = invite.Rank; + packet.OwnerGuid = calendarEvent.OwnerGuid; + packet.Status = invite.Status; + packet.TextureID = calendarEvent.TextureId; + packet.EventClubID = calendarEvent.GuildId; - Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId); - packet.EventGuildID = guild != null ? guild.GetGUID() : ObjectGuid.Empty; + receiver.SendPacket(packet); + }; if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) { - guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId); + Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId); if (guild != null) - guild.BroadcastPacket(packet); + guild.BroadcastWorker(packetBuilder); } else { Player player = Global.ObjAccessor.FindPlayer(invite.InviteeGuid); if (player != null) - player.SendPacket(packet); + packetBuilder(player); } } @@ -560,23 +598,23 @@ namespace Game if (player == null) return; - List eventInviteeList = _invites[calendarEvent.EventId]; - CalendarSendEvent packet = new(); - packet.Date = calendarEvent.Date; + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += player.GetSession().GetTimezoneOffset(); packet.Description = calendarEvent.Description; packet.EventID = calendarEvent.EventId; packet.EventName = calendarEvent.Title; packet.EventType = sendType; packet.Flags = calendarEvent.Flags; packet.GetEventType = calendarEvent.EventType; - packet.LockDate = calendarEvent.LockDate; // Always 0 ? + packet.LockDate.SetUtcTimeFromUnixTime(calendarEvent.LockDate); // Always 0 ? + if (calendarEvent.LockDate != 0) + packet.LockDate += player.GetSession().GetTimezoneOffset(); packet.OwnerGuid = calendarEvent.OwnerGuid; packet.TextureID = calendarEvent.TextureId; + packet.EventGuildID = calendarEvent.GuildId; - Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId); - packet.EventGuildID = (guild != null ? guild.GetGUID() : ObjectGuid.Empty); - + List eventInviteeList = _invites[calendarEvent.EventId]; foreach (var calendarInvite in eventInviteeList) { ObjectGuid inviteeGuid = calendarInvite.InviteeGuid; @@ -607,7 +645,8 @@ namespace Game if (player != null) { CalendarInviteRemovedAlert packet = new(); - packet.Date = calendarEvent.Date; + packet.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + packet.Date += player.GetSession().GetTimezoneOffset(); packet.EventID = calendarEvent.EventId; packet.Flags = calendarEvent.Flags; packet.Status = status; @@ -620,7 +659,7 @@ namespace Game { Player player = Global.ObjAccessor.FindPlayer(guid); if (player != null) - player.SendPacket(new CalendarClearPendingAction()); + player.SendPacket(new CalendarClearPendingAction()); } public void SendCalendarCommandResult(ObjectGuid guid, CalendarError err, string param = null) @@ -647,23 +686,33 @@ namespace Game void SendPacketToAllEventRelatives(ServerPacket packet, CalendarEvent calendarEvent) { + foreach (Player player in GetAllEventRelatives(calendarEvent)) + player.SendPacket(packet); + } + + List GetAllEventRelatives(CalendarEvent calendarEvent) + { + List relatedPlayers = new(); + // Send packet to all guild members if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) { Guild guild = Global.GuildMgr.GetGuildById(calendarEvent.GuildId); if (guild != null) - guild.BroadcastPacket(packet); + guild.BroadcastWorker(relatedPlayers.Add); } // Send packet to all invitees if event is non-guild, in other case only to non-guild invitees (packet was broadcasted for them) - List invites = _invites[calendarEvent.EventId]; - foreach (var playerCalendarEvent in invites) + var invites = _invites.LookupByKey(calendarEvent.EventId); + foreach (CalendarInvite invite in invites) { - Player player = Global.ObjAccessor.FindPlayer(playerCalendarEvent.InviteeGuid); + Player player = Global.ObjAccessor.FindConnectedPlayer(invite.InviteeGuid); if (player != null) if (!calendarEvent.IsGuildEvent() || player.GetGuildId() != calendarEvent.GuildId) - player.SendPacket(packet); + relatedPlayers.Add(player); } + + return relatedPlayers; } List _events; @@ -780,11 +829,14 @@ namespace Game return remover + ":" + Title; } - public string BuildCalendarMailBody() + public string BuildCalendarMailBody(Player invitee) { - var now = Time.UnixTimeToDateTime(Date); - uint time = Convert.ToUInt32(((now.Year - 1900) - 100) << 24 | (now.Month - 1) << 20 | (now.Day - 1) << 14 | (int)now.DayOfWeek << 11 | now.Hour << 6 | now.Minute); - return time.ToString(); + WowTime time = new(); + time.SetUtcTimeFromUnixTime(Date); + if (invitee != null) + time += invitee.GetSession().GetTimezoneOffset(); + + return time.GetPackedTime().ToString(); } public bool IsGuildEvent() { return Flags.HasAnyFlag(CalendarFlags.GuildEvent); } diff --git a/Source/Game/Conditions/ConditionManager.cs b/Source/Game/Conditions/ConditionManager.cs index efdf58bec..5b5dd3781 100644 --- a/Source/Game/Conditions/ConditionManager.cs +++ b/Source/Game/Conditions/ConditionManager.cs @@ -2224,10 +2224,18 @@ namespace Game if (condition.Time[0] != 0) { - var from = Time.GetUnixTimeFromPackedTime(condition.Time[0]); - var to = Time.GetUnixTimeFromPackedTime(condition.Time[1]); + WowTime time0 = new(); + time0.SetPackedTime(condition.Time[0]); - if (GameTime.GetGameTime() < from || GameTime.GetGameTime() > to) + if (condition.Time[1] != 0) + { + WowTime time1 = new(); + time1.SetPackedTime(condition.Time[1]); + + if (!GameTime.GetWowTime().IsInRange(time0, time1)) + return false; + } + else if (GameTime.GetWowTime() != time0) return false; } diff --git a/Source/Game/Entities/Object/WorldObject.cs b/Source/Game/Entities/Object/WorldObject.cs index be98983b8..a15abb761 100644 --- a/Source/Game/Entities/Object/WorldObject.cs +++ b/Source/Game/Entities/Object/WorldObject.cs @@ -1443,14 +1443,14 @@ namespace Game.Entities public virtual void SendMessageToSetInRange(ServerPacket data, float dist, bool self) { PacketSenderRef sender = new(data); - MessageDistDeliverer notifier = new(this, sender, dist); + MessageDistDeliverer notifier = new(this, sender, dist); Cell.VisitWorldObjects(this, notifier, dist); } public virtual void SendMessageToSet(ServerPacket data, Player skip) { PacketSenderRef sender = new(data); - var notifier = new MessageDistDeliverer(this, sender, GetVisibilityRange(), false, skip); + var notifier = new MessageDistDeliverer(this, sender, GetVisibilityRange(), false, skip); Cell.VisitWorldObjects(this, notifier, GetVisibilityRange()); } @@ -1462,7 +1462,7 @@ namespace Game.Entities if (self != null) combatLogSender.Invoke(self); - MessageDistDeliverer notifier = new(this, combatLogSender, GetVisibilityRange()); + MessageDistDeliverer notifier = new(this, combatLogSender, GetVisibilityRange()); Cell.VisitWorldObjects(this, notifier, GetVisibilityRange()); } diff --git a/Source/Game/Entities/Player/Player.cs b/Source/Game/Entities/Player/Player.cs index 01b027b98..2f8eb50c3 100644 --- a/Source/Game/Entities/Player/Player.cs +++ b/Source/Game/Entities/Player/Player.cs @@ -5557,8 +5557,8 @@ namespace Game.Entities float TimeSpeed = 0.01666667f; LoginSetTimeSpeed loginSetTimeSpeed = new(); loginSetTimeSpeed.NewSpeed = TimeSpeed; - loginSetTimeSpeed.GameTime = (uint)GameTime.GetGameTime(); - loginSetTimeSpeed.ServerTime = (uint)GameTime.GetGameTime(); + loginSetTimeSpeed.GameTime = GameTime.GetWowTime(); + loginSetTimeSpeed.ServerTime = GameTime.GetWowTime(); loginSetTimeSpeed.GameTimeHolidayOffset = 0; // @todo loginSetTimeSpeed.ServerTimeHolidayOffset = 0; // @todo SendPacket(loginSetTimeSpeed); @@ -6176,7 +6176,7 @@ namespace Game.Entities SendPacket(data); PacketSenderRef sender = new(data); - var notifier = new MessageDistDeliverer(this, sender, dist); + var notifier = new MessageDistDeliverer(this, sender, dist); Cell.VisitWorldObjects(this, notifier, dist); } @@ -6186,7 +6186,7 @@ namespace Game.Entities SendPacket(data); PacketSenderRef sender = new(data); - var notifier = new MessageDistDeliverer(this, sender, dist, own_team_only, null, required3dDist); + var notifier = new MessageDistDeliverer(this, sender, dist, own_team_only, null, required3dDist); Cell.VisitWorldObjects(this, notifier, dist); } @@ -6198,7 +6198,7 @@ namespace Game.Entities // we use World.GetMaxVisibleDistance() because i cannot see why not use a distance // update: replaced by GetMap().GetVisibilityDistance() PacketSenderRef sender = new(data); - var notifier = new MessageDistDeliverer(this, sender, GetVisibilityRange(), false, skipped_rcvr); + var notifier = new MessageDistDeliverer(this, sender, GetVisibilityRange(), false, skipped_rcvr); Cell.VisitWorldObjects(this, notifier, GetVisibilityRange()); } public override void SendMessageToSet(ServerPacket data, bool self) @@ -6467,7 +6467,7 @@ namespace Game.Entities localizer.Invoke(this); // Send to players - MessageDistDeliverer notifier = new(this, localizer, range, false, null, true); + MessageDistDeliverer notifier = new(this, localizer, range, false, null, true); Cell.VisitWorldObjects(this, notifier, range); } diff --git a/Source/Game/Guilds/Guild.cs b/Source/Game/Guilds/Guild.cs index ed125f074..e334d903d 100644 --- a/Source/Game/Guilds/Guild.cs +++ b/Source/Game/Guilds/Guild.cs @@ -200,7 +200,8 @@ namespace Game.Guilds { GuildRoster roster = new(); roster.NumAccounts = (int)m_accountsNumber; - roster.CreateDate = (uint)m_createdDate; + roster.CreateDate.SetUtcTimeFromUnixTime(m_createdDate); + roster.CreateDate += session.GetTimezoneOffset(); roster.GuildFlags = 0; bool sendOfficerNote = _HasRankRight(session.GetPlayer(), GuildRankRights.ViewOffNote); @@ -558,7 +559,7 @@ namespace Game.Guilds return; } - // Invited player cannot be invited + // Invited player cannot be invited if (pInvitee.GetGuildIdInvited() != 0) { SendCommandResult(session, GuildCommandType.InvitePlayer, GuildCommandError.AlreadyInvitedToGuild_S, name); @@ -1040,7 +1041,10 @@ namespace Game.Guilds GuildNewsPkt packet = new(); foreach (var newsLogEntry in newsLog) + { newsLogEntry.WritePacket(packet); + packet.NewsEvents.Last().CompletedDate += session.GetTimezoneOffset(); + } session.SendPacket(packet); } @@ -1535,17 +1539,20 @@ namespace Game.Guilds } } - public void BroadcastPacketIfTrackingAchievement(ServerPacket packet, uint criteriaId) + public List GetMembersTrackingCriteria(uint criteriaId) { - foreach (var member in m_members.Values) + List members = new(); + foreach (var (_, member) in m_members) { if (member.IsTrackingCriteriaId(criteriaId)) { Player player = member.FindPlayer(); if (player != null) - player.SendPacket(packet); + members.Add(player); } } + + return members; } public void MassInviteToEvent(WorldSession session, uint minLevel, uint maxLevel, GuildRankOrder minRank) @@ -1717,7 +1724,7 @@ namespace Game.Guilds player.SetGuildLevel(0); foreach (var entry in CliDB.GuildPerkSpellsStorage.Values) - player.RemoveSpell(entry.SpellID, false, false); + player.RemoveSpell(entry.SpellID, false, false); } else Global.CharacterCacheStorage.UpdateCharacterGuildId(guid, 0); @@ -1754,7 +1761,7 @@ namespace Game.Guilds return Math.Min(m_bankMoney, (ulong)_GetMemberRemainingMoney(member)); } - + public void SwapItems(Player player, byte tabId, byte slotId, byte destTabId, byte destSlotId, uint splitedAmount) { if (tabId >= _GetPurchasedTabsSize() || slotId >= GuildConst.MaxBankSlots || @@ -1805,7 +1812,7 @@ namespace Game.Guilds { return m_ranks.Find(rank => rank.GetOrder() == rankOrder); } - + // Private methods void _CreateNewBankTab() { @@ -1841,7 +1848,7 @@ namespace Game.Guilds stmt.AddValue(0, m_id); trans.Append(stmt); - _CreateRank(trans, Global.ObjectMgr.GetCypherString( CypherStrings.GuildMaster, loc), GuildRankRights.All); + _CreateRank(trans, Global.ObjectMgr.GetCypherString(CypherStrings.GuildMaster, loc), GuildRankRights.All); _CreateRank(trans, Global.ObjectMgr.GetCypherString(CypherStrings.GuildOfficer, loc), GuildRankRights.All); _CreateRank(trans, Global.ObjectMgr.GetCypherString(CypherStrings.GuildVeteran, loc), GuildRankRights.GChatListen | GuildRankRights.GChatSpeak); _CreateRank(trans, Global.ObjectMgr.GetCypherString(CypherStrings.GuildMember, loc), GuildRankRights.GChatListen | GuildRankRights.GChatSpeak); @@ -2404,9 +2411,16 @@ namespace Game.Guilds NewsLogEntry news = m_newsLog.AddEvent(trans, new NewsLogEntry(m_id, m_newsLog.GetNextGUID(), type, guid, flags, value)); DB.Characters.CommitTransaction(trans); - GuildNewsPkt newsPacket = new(); - news.WritePacket(newsPacket); - BroadcastPacket(newsPacket); + var packetBuilder = (Player receiver) => + { + GuildNewsPkt newsPacket = new(); + news.WritePacket(newsPacket); + newsPacket.NewsEvents.Last().CompletedDate += receiver.GetSession().GetTimezoneOffset(); + + receiver.SendPacket(newsPacket); + }; + + BroadcastWorker(packetBuilder); } bool HasAchieved(uint achievementId) @@ -2432,6 +2446,7 @@ namespace Game.Guilds GuildNewsPkt newsPacket = new(); newsLog.WritePacket(newsPacket); + newsPacket.NewsEvents.Last().CompletedDate += session.GetTimezoneOffset(); session.SendPacket(newsPacket); } @@ -2455,6 +2470,17 @@ namespace Game.Guilds } } + public void BroadcastWorker(Action _do, Player except = null) + { + foreach (var member in m_members.Values) + { + Player player = member.FindPlayer(); + if (player != null) + if (player != except) + _do.Invoke(player); + } + } + public int GetMembersCount() { return m_members.Count; } public GuildAchievementMgr GetAchievementMgr() { return m_achievementSys; } @@ -3077,7 +3103,7 @@ namespace Game.Guilds GuildNewsEvent newsEvent = new(); newsEvent.Id = (int)GetGUID(); newsEvent.MemberGuid = GetPlayerGuid(); - newsEvent.CompletedDate = (uint)GetTimestamp(); + newsEvent.CompletedDate.SetUtcTimeFromUnixTime(GetTimestamp()); newsEvent.Flags = GetFlags(); newsEvent.Type = (int)GetNewsType(); @@ -3116,9 +3142,9 @@ namespace Game.Guilds // Checks if new log entry can be added to holder public bool CanInsert() { return m_log.Count < m_maxRecords; } - + public byte GetSize() { return (byte)m_log.Count; } - + public void LoadEvent(T entry) { if (m_nextGUID == GuildConst.EventLogGuidUndefined) @@ -3540,7 +3566,7 @@ namespace Game.Guilds { return ValidateEmblemColors(m_style, m_color, m_borderStyle, m_borderColor, m_backgroundColor); } - + public static bool ValidateEmblemColors(uint style, uint color, uint borderStyle, uint borderColor, uint backgroundColor) { return CliDB.GuildColorBackgroundStorage.ContainsKey(backgroundColor) && @@ -3650,7 +3676,7 @@ namespace Game.Guilds { m_pPlayer.SendEquipError(result, item); } - + public abstract bool IsBank(); // Initializes item. Returns true, if item exists, false otherwise. public abstract bool InitItem(); @@ -3823,7 +3849,7 @@ namespace Game.Guilds public override void LogBankEvent(SQLTransaction trans, MoveItemData pFrom, uint count) { - Cypher.Assert(pFrom.GetItem() != null); + Cypher.Assert(pFrom.GetItem() != null); if (pFrom.IsBank()) // Bank . Bank m_pGuild._LogBankEvent(trans, GuildBankEventLogTypes.MoveItem, pFrom.GetContainer(), m_pPlayer.GetGUID().GetCounter(), diff --git a/Source/Game/Handlers/AuthenticationHandler.cs b/Source/Game/Handlers/AuthenticationHandler.cs index 48a891679..5bff6d9cb 100644 --- a/Source/Game/Handlers/AuthenticationHandler.cs +++ b/Source/Game/Handlers/AuthenticationHandler.cs @@ -1,8 +1,10 @@ // Copyright (c) CypherCore All rights reserved. // Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. +using Framework; using Framework.Constants; using Game.Networking.Packets; +using System; namespace Game { @@ -68,11 +70,14 @@ namespace Game public void SendSetTimeZoneInformation() { - // @todo: replace dummy values + TimeSpan timezoneOffset = Timezone.GetSystemZoneOffset(); + string realTimezone = Timezone.GetSystemZoneName(); + string clientSupportedTZ = Timezone.FindClosestClientSupportedTimezone(realTimezone, timezoneOffset); + SetTimeZoneInformation packet = new(); - packet.ServerTimeTZ = "Europe/Paris"; - packet.GameTimeTZ = "Europe/Paris"; - packet.ServerRegionalTZ = "Europe/Paris"; + packet.ServerTimeTZ = clientSupportedTZ; + packet.GameTimeTZ = clientSupportedTZ; + packet.ServerRegionalTZ = clientSupportedTZ; SendPacket(packet);//enabled it } diff --git a/Source/Game/Handlers/CalendarHandler.cs b/Source/Game/Handlers/CalendarHandler.cs index 24fa4e4f9..538f995ac 100644 --- a/Source/Game/Handlers/CalendarHandler.cs +++ b/Source/Game/Handlers/CalendarHandler.cs @@ -21,10 +21,8 @@ namespace Game { ObjectGuid guid = GetPlayer().GetGUID(); - long currTime = GameTime.GetGameTime(); - CalendarSendCalendar packet = new(); - packet.ServerTime = currTime; + packet.ServerTime = GameTime.GetWowTime(); var playerInvites = Global.CalendarMgr.GetPlayerInvites(guid); foreach (var invite in playerInvites) @@ -47,7 +45,8 @@ namespace Game { CalendarSendCalendarEventInfo eventInfo = new(); eventInfo.EventID = calendarEvent.EventId; - eventInfo.Date = calendarEvent.Date; + eventInfo.Date.SetUtcTimeFromUnixTime(calendarEvent.Date); + eventInfo.Date += GetTimezoneOffset(); eventInfo.EventClubID = calendarEvent.GuildId; eventInfo.EventName = calendarEvent.Title; eventInfo.EventType = calendarEvent.EventType; @@ -95,11 +94,10 @@ namespace Game { ObjectGuid guid = GetPlayer().GetGUID(); - calendarAddEvent.EventInfo.Time = Time.LocalTimeToUTCTime(calendarAddEvent.EventInfo.Time); + calendarAddEvent.EventInfo.Time -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarAddEvent.EventInfo.Time < (GameTime.GetGameTime() - 86400L)) + if (calendarAddEvent.EventInfo.Time < GameTime.GetUtcWowTime()) { Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventPassed); return; @@ -141,7 +139,7 @@ namespace Game SetCalendarEventCreationCooldown(GameTime.GetGameTime() + SharedConst.CalendarCreateEventCooldown); CalendarEvent calendarEvent = new(Global.CalendarMgr.GetFreeEventId(), guid, 0, (CalendarEventType)calendarAddEvent.EventInfo.EventType, calendarAddEvent.EventInfo.TextureID, - calendarAddEvent.EventInfo.Time, (CalendarFlags)calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, 0); + calendarAddEvent.EventInfo.Time.GetUnixTimeFromUtcTime(), (CalendarFlags)calendarAddEvent.EventInfo.Flags, calendarAddEvent.EventInfo.Title, calendarAddEvent.EventInfo.Description, 0); if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) calendarEvent.GuildId = _player.GetGuildId(); @@ -180,11 +178,10 @@ namespace Game ObjectGuid guid = GetPlayer().GetGUID(); long oldEventTime; - calendarUpdateEvent.EventInfo.Time = Time.LocalTimeToUTCTime(calendarUpdateEvent.EventInfo.Time); + calendarUpdateEvent.EventInfo.Time -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarUpdateEvent.EventInfo.Time < (GameTime.GetGameTime() - 86400L)) + if (calendarUpdateEvent.EventInfo.Time < GameTime.GetUtcWowTime()) return; CalendarEvent calendarEvent = Global.CalendarMgr.GetEvent(calendarUpdateEvent.EventInfo.EventID); @@ -194,7 +191,7 @@ namespace Game calendarEvent.EventType = (CalendarEventType)calendarUpdateEvent.EventInfo.EventType; calendarEvent.Flags = (CalendarFlags)calendarUpdateEvent.EventInfo.Flags; - calendarEvent.Date = calendarUpdateEvent.EventInfo.Time; + calendarEvent.Date = calendarUpdateEvent.EventInfo.Time.GetUnixTimeFromUtcTime(); calendarEvent.TextureId = (int)calendarUpdateEvent.EventInfo.TextureID; calendarEvent.Title = calendarUpdateEvent.EventInfo.Title; calendarEvent.Description = calendarUpdateEvent.EventInfo.Description; @@ -218,11 +215,10 @@ namespace Game { ObjectGuid guid = GetPlayer().GetGUID(); - calendarCopyEvent.Date = Time.LocalTimeToUTCTime(calendarCopyEvent.Date); + calendarCopyEvent.Date -= GetTimezoneOffset(); // prevent events in the past - // To Do: properly handle timezones and remove the "- time_t(86400L)" hack - if (calendarCopyEvent.Date < (GameTime.GetGameTime() - 86400L)) + if (calendarCopyEvent.Date < GameTime.GetUtcWowTime()) { Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventPassed); return; @@ -275,7 +271,7 @@ namespace Game SetCalendarEventCreationCooldown(GameTime.GetGameTime() + SharedConst.CalendarCreateEventCooldown); CalendarEvent newEvent = new(oldEvent, Global.CalendarMgr.GetFreeEventId()); - newEvent.Date = calendarCopyEvent.Date; + newEvent.Date = calendarCopyEvent.Date.GetUnixTimeFromUtcTime(); Global.CalendarMgr.AddEvent(newEvent, CalendarSendEventType.Copy); var invites = Global.CalendarMgr.GetEventInvites(calendarCopyEvent.EventID); @@ -536,7 +532,7 @@ namespace Game return; CalendarRaidLockoutUpdated calendarRaidLockoutUpdated = new(); - calendarRaidLockoutUpdated.ServerTime = GameTime.GetGameTime(); + calendarRaidLockoutUpdated.ServerTime = GameTime.GetWowTime(); calendarRaidLockoutUpdated.MapID = setSavedInstanceExtend.MapID; calendarRaidLockoutUpdated.DifficultyID = setSavedInstanceExtend.DifficultyID; calendarRaidLockoutUpdated.OldTimeRemaining = (int)Math.Max((expiryTimes.Item1 - GameTime.GetSystemTime()).TotalSeconds, 0); @@ -548,7 +544,7 @@ namespace Game { CalendarRaidLockoutAdded calendarRaidLockoutAdded = new(); calendarRaidLockoutAdded.InstanceID = instanceLock.GetInstanceId(); - calendarRaidLockoutAdded.ServerTime = (uint)GameTime.GetGameTime(); + calendarRaidLockoutAdded.ServerTime = GameTime.GetWowTime(); calendarRaidLockoutAdded.MapID = (int)instanceLock.GetMapId(); calendarRaidLockoutAdded.DifficultyID = instanceLock.GetDifficultyId(); calendarRaidLockoutAdded.TimeRemaining = (int)(instanceLock.GetEffectiveExpiryTime() - GameTime.GetSystemTime()).TotalSeconds; diff --git a/Source/Game/Maps/GridNotifiers.cs b/Source/Game/Maps/GridNotifiers.cs index 38aee94c3..01eb5e2df 100644 --- a/Source/Game/Maps/GridNotifiers.cs +++ b/Source/Game/Maps/GridNotifiers.cs @@ -387,17 +387,30 @@ namespace Game.Maps } } - public class MessageDistDeliverer : Notifier where T : IDoWork + public class MessageDistDeliverer : Notifier { WorldObject i_source; - T i_packetSender; + Action i_packetSender; PhaseShift i_phaseShift; float i_distSq; Team team; Player skipped_receiver; bool required3dDist; - public MessageDistDeliverer(WorldObject src, T packetSender, float dist, bool own_team_only = false, Player skipped = null, bool req3dDist = false) + public MessageDistDeliverer(WorldObject src, IDoWork packetSender, float dist, bool own_team_only = false, Player skipped = null, bool req3dDist = false) + { + i_source = src; + i_packetSender = packetSender.Invoke; + i_phaseShift = src.GetPhaseShift(); + i_distSq = dist * dist; + if (own_team_only && src.IsPlayer()) + team = src.ToPlayer().GetEffectiveTeam(); + + skipped_receiver = skipped; + required3dDist = req3dDist; + } + + public MessageDistDeliverer(WorldObject src, Action packetSender, float dist, bool own_team_only = false, Player skipped = null, bool req3dDist = false) { i_source = src; i_packetSender = packetSender; diff --git a/Source/Game/Networking/Packets/AchievementPackets.cs b/Source/Game/Networking/Packets/AchievementPackets.cs index 7271d58ed..3d797d983 100644 --- a/Source/Game/Networking/Packets/AchievementPackets.cs +++ b/Source/Game/Networking/Packets/AchievementPackets.cs @@ -60,7 +60,7 @@ namespace Game.Networking.Packets _worldPacket.WritePackedGuid(PlayerGUID); _worldPacket.WriteUInt32(Unused_10_1_5); _worldPacket.WriteUInt32(Flags); - _worldPacket.WritePackedTime(CurrentTime); + CurrentTime.Write(_worldPacket); _worldPacket.WriteInt64(ElapsedTime); _worldPacket.WriteInt64(CreationTime); _worldPacket.WriteBit(RafAcceptanceID.HasValue); @@ -75,7 +75,7 @@ namespace Game.Networking.Packets public ObjectGuid PlayerGUID; public uint Unused_10_1_5; public uint Flags; - public long CurrentTime; + public WowTime CurrentTime; public long ElapsedTime; public long CreationTime; public ulong? RafAcceptanceID; @@ -128,7 +128,7 @@ namespace Game.Networking.Packets _worldPacket.WritePackedGuid(Sender); _worldPacket.WritePackedGuid(Earner); _worldPacket.WriteUInt32(AchievementID); - _worldPacket.WritePackedTime(Time); + Time.Write(_worldPacket); _worldPacket.WriteUInt32(EarnerNativeRealm); _worldPacket.WriteUInt32(EarnerVirtualRealm); _worldPacket.WriteBit(Initial); @@ -139,7 +139,7 @@ namespace Game.Networking.Packets public uint EarnerNativeRealm; public uint EarnerVirtualRealm; public uint AchievementID; - public long Time; + public WowTime Time; public bool Initial; public ObjectGuid Sender; } @@ -176,7 +176,7 @@ namespace Game.Networking.Packets _worldPacket.WriteUInt32(progress.CriteriaID); _worldPacket.WriteInt64(progress.DateCreated); _worldPacket.WriteInt64(progress.DateStarted); - _worldPacket.WritePackedTime(progress.DateUpdated); + progress.DateUpdated.Write(_worldPacket); _worldPacket.WriteUInt32(0); // this is a hack. this is a packed time written as int64 (progress.DateUpdated) _worldPacket.WriteUInt64(progress.Quantity); _worldPacket.WritePackedGuid(progress.PlayerGUID); @@ -222,12 +222,12 @@ namespace Game.Networking.Packets { _worldPacket.WritePackedGuid(GuildGUID); _worldPacket.WriteUInt32(AchievementID); - _worldPacket.WritePackedTime(TimeDeleted); + TimeDeleted.Write(_worldPacket); } public ObjectGuid GuildGUID; public uint AchievementID; - public long TimeDeleted; + public WowTime TimeDeleted; } public class GuildAchievementEarned : ServerPacket @@ -238,12 +238,12 @@ namespace Game.Networking.Packets { _worldPacket.WritePackedGuid(GuildGUID); _worldPacket.WriteUInt32(AchievementID); - _worldPacket.WritePackedTime(TimeEarned); + TimeEarned.Write(_worldPacket); } public uint AchievementID; public ObjectGuid GuildGUID; - public long TimeEarned; + public WowTime TimeEarned; } public class AllGuildAchievements : ServerPacket @@ -301,14 +301,14 @@ namespace Game.Networking.Packets public void Write(WorldPacket data) { data.WriteUInt32(Id); - data.WritePackedTime(Date); + Date.Write(data); data.WritePackedGuid(Owner); data.WriteUInt32(VirtualRealmAddress); data.WriteUInt32(NativeRealmAddress); } public uint Id; - public long Date; + public WowTime Date; public ObjectGuid Owner; public uint VirtualRealmAddress; public uint NativeRealmAddress; @@ -323,7 +323,7 @@ namespace Game.Networking.Packets data.WritePackedGuid(Player); data.WriteUInt32(Unused_10_1_5); data.WriteUInt32(Flags); - data.WritePackedTime(Date); + Date.Write(data); data.WriteInt64(TimeFromStart); data.WriteInt64(TimeFromCreate); data.WriteBit(RafAcceptanceID.HasValue); @@ -338,7 +338,7 @@ namespace Game.Networking.Packets public ObjectGuid Player; public uint Unused_10_1_5; public uint Flags; - public long Date; + public WowTime Date; public long TimeFromStart; public long TimeFromCreate; public ulong? RafAcceptanceID; @@ -349,7 +349,7 @@ namespace Game.Networking.Packets public uint CriteriaID; public long DateCreated; public long DateStarted; - public long DateUpdated; + public WowTime DateUpdated; public ulong Quantity; public ObjectGuid PlayerGUID; public int Unused_10_1_5; diff --git a/Source/Game/Networking/Packets/CalendarPackets.cs b/Source/Game/Networking/Packets/CalendarPackets.cs index 836535163..d6ebc16cd 100644 --- a/Source/Game/Networking/Packets/CalendarPackets.cs +++ b/Source/Game/Networking/Packets/CalendarPackets.cs @@ -101,13 +101,14 @@ namespace Game.Networking.Packets EventID = _worldPacket.ReadUInt64(); ModeratorID = _worldPacket.ReadUInt64(); EventClubID = _worldPacket.ReadUInt64(); - Date = _worldPacket.ReadPackedTime(); + Date = new(); + Date.Read(_worldPacket); } public ulong ModeratorID; public ulong EventID; public ulong EventClubID; - public long Date; + public WowTime Date; } class CalendarInviteAdded : ServerPacket @@ -122,14 +123,14 @@ namespace Game.Networking.Packets _worldPacket.WriteUInt8(Level); _worldPacket.WriteUInt8((byte)Status); _worldPacket.WriteUInt8(Type); - _worldPacket.WritePackedTime(ResponseTime); + ResponseTime.Write(_worldPacket); _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); } public ulong InviteID; - public long ResponseTime; + public WowTime ResponseTime; public byte Level = 100; public ObjectGuid InviteGuid; public ulong EventID; @@ -144,7 +145,7 @@ namespace Game.Networking.Packets public override void Write() { - _worldPacket.WritePackedTime(ServerTime); + ServerTime.Write(_worldPacket); _worldPacket.WriteInt32(Invites.Count); _worldPacket.WriteInt32(Events.Count); _worldPacket.WriteInt32(RaidLockouts.Count); @@ -159,7 +160,7 @@ namespace Game.Networking.Packets Event.Write(_worldPacket); } - public long ServerTime; + public WowTime ServerTime; public List Invites = new(); public List RaidLockouts = new(); public List Events = new(); @@ -177,9 +178,9 @@ namespace Game.Networking.Packets _worldPacket.WriteUInt8((byte)GetEventType); _worldPacket.WriteInt32(TextureID); _worldPacket.WriteUInt32((uint)Flags); - _worldPacket.WritePackedTime(Date); - _worldPacket.WriteUInt32((uint)LockDate); - _worldPacket.WritePackedGuid(EventGuildID); + Date.Write(_worldPacket); + LockDate.Write(_worldPacket); + _worldPacket.WriteUInt64(EventGuildID); _worldPacket.WriteInt32(Invites.Count); _worldPacket.WriteBits(EventName.GetByteCount(), 8); @@ -194,10 +195,10 @@ namespace Game.Networking.Packets } public ObjectGuid OwnerGuid; - public ObjectGuid EventGuildID; + public ulong EventGuildID; public ulong EventID; - public long Date; - public long LockDate; + public WowTime Date; + public WowTime LockDate; public CalendarFlags Flags; public int TextureID; public CalendarEventType GetEventType; @@ -214,11 +215,11 @@ namespace Game.Networking.Packets public override void Write() { _worldPacket.WriteUInt64(EventID); - _worldPacket.WritePackedTime(Date); + Date.Write(_worldPacket); _worldPacket.WriteUInt32((uint)Flags); _worldPacket.WriteUInt8((byte)EventType); _worldPacket.WriteInt32(TextureID); - _worldPacket.WritePackedGuid(EventGuildID); + _worldPacket.WriteUInt64(EventClubID); _worldPacket.WriteUInt64(InviteID); _worldPacket.WriteUInt8((byte)Status); _worldPacket.WriteUInt8((byte)ModeratorStatus); @@ -233,12 +234,12 @@ namespace Game.Networking.Packets } public ObjectGuid OwnerGuid; - public ObjectGuid EventGuildID; + public ulong EventClubID; public ObjectGuid InvitedByGuid; public ulong InviteID; public ulong EventID; public CalendarFlags Flags; - public long Date; + public WowTime Date; public int TextureID; public CalendarInviteStatus Status; public CalendarEventType EventType; @@ -295,10 +296,10 @@ namespace Game.Networking.Packets { _worldPacket.WritePackedGuid(InviteGuid); _worldPacket.WriteUInt64(EventID); - _worldPacket.WritePackedTime(Date); + Date.Write(_worldPacket); _worldPacket.WriteUInt32((uint)Flags); _worldPacket.WriteUInt8((byte)Status); - _worldPacket.WritePackedTime(ResponseTime); + ResponseTime.Write(_worldPacket); _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); @@ -308,8 +309,8 @@ namespace Game.Networking.Packets public ulong EventID; public CalendarInviteStatus Status; public bool ClearPending; - public long ResponseTime; - public long Date; + public WowTime ResponseTime; + public WowTime Date; public ObjectGuid InviteGuid; } @@ -360,13 +361,13 @@ namespace Game.Networking.Packets public override void Write() { _worldPacket.WriteUInt64(EventID); - _worldPacket.WritePackedTime(Date); + Date.Write(_worldPacket); _worldPacket.WriteUInt32((uint)Flags); _worldPacket.WriteUInt8((byte)Status); } public ulong EventID; - public long Date; + public WowTime Date; public CalendarFlags Flags; public CalendarInviteStatus Status; } @@ -386,9 +387,9 @@ namespace Game.Networking.Packets { _worldPacket.WriteUInt64(EventID); - _worldPacket.WritePackedTime(OriginalDate); - _worldPacket.WritePackedTime(Date); - _worldPacket.WriteUInt32((uint)LockDate); + OriginalDate.Write(_worldPacket); + Date.Write(_worldPacket); + LockDate.Write(_worldPacket); _worldPacket.WriteUInt32((uint)Flags); _worldPacket.WriteInt32(TextureID); _worldPacket.WriteUInt8((byte)EventType); @@ -403,10 +404,10 @@ namespace Game.Networking.Packets } public ulong EventID; - public long Date; + public WowTime Date; public CalendarFlags Flags; - public long LockDate; - public long OriginalDate; + public WowTime LockDate; + public WowTime OriginalDate; public int TextureID; public CalendarEventType EventType; public bool ClearPending; @@ -421,14 +422,14 @@ namespace Game.Networking.Packets public override void Write() { _worldPacket.WriteUInt64(EventID); - _worldPacket.WritePackedTime(Date); + Date.Write(_worldPacket); _worldPacket.WriteBit(ClearPending); _worldPacket.FlushBits(); } public ulong EventID; - public long Date; + public WowTime Date; public bool ClearPending; } @@ -576,7 +577,7 @@ namespace Game.Networking.Packets public override void Write() { _worldPacket.WriteUInt64(InstanceID); - _worldPacket.WriteUInt32(ServerTime); + ServerTime.Write(_worldPacket); _worldPacket.WriteInt32(MapID); _worldPacket.WriteUInt32((uint)DifficultyID); _worldPacket.WriteInt32(TimeRemaining); @@ -585,7 +586,7 @@ namespace Game.Networking.Packets public ulong InstanceID; public Difficulty DifficultyID; public int TimeRemaining; - public uint ServerTime; + public WowTime ServerTime; public int MapID; } @@ -611,14 +612,14 @@ namespace Game.Networking.Packets public override void Write() { - _worldPacket.WritePackedTime(ServerTime); + ServerTime.Write(_worldPacket); _worldPacket.WriteInt32(MapID); _worldPacket.WriteUInt32(DifficultyID); _worldPacket.WriteInt32(OldTimeRemaining); _worldPacket.WriteInt32(NewTimeRemaining); } - public long ServerTime; + public WowTime ServerTime; public int MapID; public uint DifficultyID; public int NewTimeRemaining; @@ -754,7 +755,7 @@ namespace Game.Networking.Packets ClubId = data.ReadUInt64(); EventType = data.ReadUInt8(); TextureID = data.ReadInt32(); - Time = data.ReadPackedTime(); + Time.Read(data); Flags = data.ReadUInt32(); var InviteCount = data.ReadUInt32(); @@ -777,7 +778,7 @@ namespace Game.Networking.Packets public string Description; public byte EventType; public int TextureID; - public long Time; + public WowTime Time; public uint Flags; public CalendarAddEventInviteInfo[] Invites = new CalendarAddEventInviteInfo[(int)SharedConst.CalendarMaxInvites]; } @@ -791,7 +792,8 @@ namespace Game.Networking.Packets ModeratorID = data.ReadUInt64(); EventType = data.ReadUInt8(); TextureID = data.ReadUInt32(); - Time = data.ReadPackedTime(); + Time = new(); + Time.Read(data); Flags = data.ReadUInt32(); byte titleLen = data.ReadBits(8); @@ -808,7 +810,7 @@ namespace Game.Networking.Packets public string Description; public byte EventType; public uint TextureID; - public long Time; + public WowTime Time; public uint Flags; } @@ -856,7 +858,7 @@ namespace Game.Networking.Packets { data.WriteUInt64(EventID); data.WriteUInt8((byte)EventType); - data.WritePackedTime(Date); + Date.Write(data); data.WriteUInt32((uint)Flags); data.WriteInt32(TextureID); data.WriteUInt64(EventClubID); @@ -870,7 +872,7 @@ namespace Game.Networking.Packets public ulong EventID; public string EventName; public CalendarEventType EventType; - public long Date; + public WowTime Date; public CalendarFlags Flags; public int TextureID; public ulong EventClubID; diff --git a/Source/Game/Networking/Packets/GuildPackets.cs b/Source/Game/Networking/Packets/GuildPackets.cs index 139d804e2..25ada44df 100644 --- a/Source/Game/Networking/Packets/GuildPackets.cs +++ b/Source/Game/Networking/Packets/GuildPackets.cs @@ -112,7 +112,7 @@ namespace Game.Networking.Packets public override void Write() { _worldPacket.WriteInt32(NumAccounts); - _worldPacket.WritePackedTime(CreateDate); + CreateDate.Write(_worldPacket); _worldPacket.WriteInt32(GuildFlags); _worldPacket.WriteInt32(MemberData.Count); _worldPacket.WriteBits(WelcomeText.GetByteCount(), 11); @@ -128,7 +128,7 @@ namespace Game.Networking.Packets public List MemberData; public string WelcomeText; public string InfoText; - public uint CreateDate; + public WowTime CreateDate; public int NumAccounts; public int GuildFlags; } @@ -1765,7 +1765,7 @@ namespace Game.Networking.Packets public void Write(WorldPacket data) { data.WriteInt32(Id); - data.WritePackedTime(CompletedDate); + CompletedDate.Write(data); data.WriteInt32(Type); data.WriteInt32(Flags); @@ -1786,7 +1786,7 @@ namespace Game.Networking.Packets } public int Id; - public uint CompletedDate; + public WowTime CompletedDate; public int Type; public int Flags; public int[] Data = new int[2]; diff --git a/Source/Game/Networking/Packets/MiscPackets.cs b/Source/Game/Networking/Packets/MiscPackets.cs index 426be76c3..0486b7edf 100644 --- a/Source/Game/Networking/Packets/MiscPackets.cs +++ b/Source/Game/Networking/Packets/MiscPackets.cs @@ -62,8 +62,8 @@ namespace Game.Networking.Packets public override void Write() { - _worldPacket.WritePackedTime(ServerTime); - _worldPacket.WritePackedTime(GameTime); + ServerTime.Write(_worldPacket); + GameTime.Write(_worldPacket); _worldPacket.WriteFloat(NewSpeed); _worldPacket.WriteInt32(ServerTimeHolidayOffset); _worldPacket.WriteInt32(GameTimeHolidayOffset); @@ -71,8 +71,8 @@ namespace Game.Networking.Packets public float NewSpeed; public int ServerTimeHolidayOffset; - public uint GameTime; - public uint ServerTime; + public WowTime GameTime; + public WowTime ServerTime; public int GameTimeHolidayOffset; } diff --git a/Source/Game/Quest/QuestObjectiveCriteriaManager.cs b/Source/Game/Quest/QuestObjectiveCriteriaManager.cs index 44fa29142..84f051a96 100644 --- a/Source/Game/Quest/QuestObjectiveCriteriaManager.cs +++ b/Source/Game/Quest/QuestObjectiveCriteriaManager.cs @@ -164,16 +164,17 @@ namespace Game public override void SendAllData(Player receiver) { - foreach (var pair in _criteriaProgress) + foreach (var (id, criteriaProgres) in _criteriaProgress) { CriteriaUpdate criteriaUpdate = new(); - criteriaUpdate.CriteriaID = pair.Key; - criteriaUpdate.Quantity = pair.Value.Counter; + criteriaUpdate.CriteriaID = id; + criteriaUpdate.Quantity = criteriaProgres.Counter; criteriaUpdate.PlayerGUID = _owner.GetGUID(); criteriaUpdate.Flags = 0; - criteriaUpdate.CurrentTime = pair.Value.Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(criteriaProgres.Date); + criteriaUpdate.CurrentTime += _owner.GetSession().GetTimezoneOffset(); criteriaUpdate.CreationTime = 0; SendPacket(criteriaUpdate); @@ -208,7 +209,8 @@ namespace Game if (criteria.Entry.StartTimer != 0) criteriaUpdate.Flags = timedCompleted ? 1 : 0u; // 1 is for keeping the counter at 0 in client - criteriaUpdate.CurrentTime = progress.Date; + criteriaUpdate.CurrentTime.SetUtcTimeFromUnixTime(progress.Date); + criteriaUpdate.CurrentTime += _owner.GetSession().GetTimezoneOffset(); criteriaUpdate.ElapsedTime = (uint)timeElapsed.TotalSeconds; criteriaUpdate.CreationTime = 0; diff --git a/Source/Game/Scenarios/Scenario.cs b/Source/Game/Scenarios/Scenario.cs index a0db7294e..bc7f40466 100644 --- a/Source/Game/Scenarios/Scenario.cs +++ b/Source/Game/Scenarios/Scenario.cs @@ -107,9 +107,12 @@ namespace Game.Scenarios } } - ScenarioState scenarioState = new(); - BuildScenarioState(scenarioState); - SendPacket(scenarioState); + DoForAllPlayers(receiver => + { + ScenarioState scenarioState = new(); + BuildScenarioStateFor(receiver, scenarioState); + receiver.SendPacket(scenarioState); + }); } public virtual void OnPlayerEnter(Player player) @@ -153,18 +156,22 @@ namespace Game.Scenarios public override void SendCriteriaUpdate(Criteria criteria, CriteriaProgress progress, TimeSpan timeElapsed, bool timedCompleted) { - ScenarioProgressUpdate progressUpdate = new(); - progressUpdate.CriteriaProgress.Id = criteria.Id; - progressUpdate.CriteriaProgress.Quantity = progress.Counter; - progressUpdate.CriteriaProgress.Player = progress.PlayerGUID; - progressUpdate.CriteriaProgress.Date = progress.Date; - if (criteria.Entry.StartTimer != 0) - progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0u; + DoForAllPlayers(receiver => + { + ScenarioProgressUpdate progressUpdate = new(); + progressUpdate.CriteriaProgress.Id = criteria.Id; + progressUpdate.CriteriaProgress.Quantity = progress.Counter; + progressUpdate.CriteriaProgress.Player = progress.PlayerGUID; + progressUpdate.CriteriaProgress.Date.SetUtcTimeFromUnixTime(progress.Date); + progressUpdate.CriteriaProgress.Date += receiver.GetSession().GetTimezoneOffset(); + if (criteria.Entry.StartTimer != 0) + progressUpdate.CriteriaProgress.Flags = timedCompleted ? 1 : 0u; - progressUpdate.CriteriaProgress.TimeFromStart = (uint)timeElapsed.TotalSeconds; - progressUpdate.CriteriaProgress.TimeFromCreate = 0; + progressUpdate.CriteriaProgress.TimeFromStart = (uint)timeElapsed.TotalSeconds; + progressUpdate.CriteriaProgress.TimeFromCreate = 0; - SendPacket(progressUpdate); + receiver.SendPacket(progressUpdate); + }); } public override bool CanUpdateCriteriaTree(Criteria criteria, CriteriaTree tree, Player referencePlayer) @@ -225,25 +232,30 @@ namespace Game.Scenarios return IsCompletedCriteriaTree(tree); } - - public override void SendPacket(ServerPacket data) + + public void DoForAllPlayers(Action worker) { foreach (ObjectGuid guid in _players) { Player player = Global.ObjAccessor.GetPlayer(_map, guid); if (player != null) - player.SendPacket(data); + worker(player); } } - void BuildScenarioState(ScenarioState scenarioState) + public override void SendPacket(ServerPacket data) + { + DoForAllPlayers(player => player.SendPacket(data)); + } + + void BuildScenarioStateFor(Player player, ScenarioState scenarioState) { scenarioState.ScenarioGUID = _guid; scenarioState.ScenarioID = (int)_data.Entry.Id; ScenarioStepRecord step = GetStep(); if (step != null) scenarioState.CurrentStep = (int)step.Id; - scenarioState.CriteriaProgress = GetCriteriasProgress(); + scenarioState.CriteriaProgress = GetCriteriasProgressFor(player); scenarioState.BonusObjectives = GetBonusObjectivesData(); // Don't know exactly what this is for, but seems to contain list of scenario steps that we're either on or that are completed foreach (var state in _stepStates) @@ -297,11 +309,11 @@ namespace Game.Scenarios return lastStep; } - + public void SendScenarioState(Player player) { ScenarioState scenarioState = new(); - BuildScenarioState(scenarioState); + BuildScenarioStateFor(player, scenarioState); player.SendPacket(scenarioState); } @@ -325,21 +337,19 @@ namespace Game.Scenarios return bonusObjectivesData; } - List GetCriteriasProgress() + List GetCriteriasProgressFor(Player player) { List criteriasProgress = new(); - if (!_criteriaProgress.Empty()) + foreach (var (criteriaId, progress) in _criteriaProgress) { - foreach (var pair in _criteriaProgress) - { - CriteriaProgressPkt criteriaProgress = new(); - criteriaProgress.Id = pair.Key; - criteriaProgress.Quantity = pair.Value.Counter; - criteriaProgress.Date = pair.Value.Date; - criteriaProgress.Player = pair.Value.PlayerGUID; - criteriasProgress.Add(criteriaProgress); - } + CriteriaProgressPkt criteriaProgress = new(); + criteriaProgress.Id = criteriaId; + criteriaProgress.Quantity = progress.Counter; + criteriaProgress.Date.SetUtcTimeFromUnixTime(progress.Date); + criteriaProgress.Date += player.GetSession().GetTimezoneOffset(); + criteriaProgress.Player = progress.PlayerGUID; + criteriasProgress.Add(criteriaProgress); } return criteriasProgress; diff --git a/Source/Game/Time/GameTime.cs b/Source/Game/Time/GameTime.cs index fd8c6566d..e6ae1df1d 100644 --- a/Source/Game/Time/GameTime.cs +++ b/Source/Game/Time/GameTime.cs @@ -1,4 +1,8 @@ -using System; +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using Framework; +using System; public class GameTime { @@ -12,6 +16,9 @@ public class GameTime static DateTime _dateTime; + static WowTime UtcWow; + static WowTime Wow; + public static long GetStartTime() { return StartTime; @@ -47,6 +54,16 @@ public class GameTime return _dateTime; } + public static WowTime GetUtcWowTime() + { + return UtcWow; + } + + public static WowTime GetWowTime() + { + return Wow; + } + public static void UpdateGameTimers() { _gameTime = Time.UnixTime; @@ -55,5 +72,8 @@ public class GameTime _gameTimeSteadyPoint = DateTime.Now; _dateTime = Time.UnixTimeToDateTime(_gameTime); + + UtcWow.SetUtcTimeFromUnixTime(_gameTime); + Wow = UtcWow + Timezone.GetSystemZoneOffsetAt(_gameTimeSystemPoint); } } diff --git a/Source/Game/Time/Updatetime.cs b/Source/Game/Time/Updatetime.cs index e9508beae..7952b5998 100644 --- a/Source/Game/Time/Updatetime.cs +++ b/Source/Game/Time/Updatetime.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using System; namespace Game { diff --git a/Source/Game/Time/WowTime.cs b/Source/Game/Time/WowTime.cs new file mode 100644 index 000000000..bcf11f0cf --- /dev/null +++ b/Source/Game/Time/WowTime.cs @@ -0,0 +1,235 @@ +// Copyright (c) CypherCore All rights reserved. +// Licensed under the GNU GENERAL PUBLIC LICENSE. See LICENSE file in the project root for full license information. + +using Game.Networking; +using System; + +public struct WowTime : IComparable +{ + int _year = -1; + int _month = -1; + int _monthDay = -1; + int _weekDay = -1; + int _hour = -1; + int _minute = -1; + int _flags = -1; + int _holidayOffset = 0; + + public WowTime() { } + + public uint GetPackedTime() + { + return (uint)(((_year % 100) & 0x1F) << 24 + | (_month & 0xF) << 20 + | (_monthDay & 0x3F) << 14 + | (_weekDay & 0x7) << 11 + | (_hour & 0x1F) << 6 + | (_minute & 0x3F) + | (_flags & 0x3) << 29); + } + + public void SetPackedTime(uint packedTime) + { + _year = (int)(packedTime >> 24) & 0x1F; + if (_year == 31) + _year = -1; + + _month = (int)((packedTime >> 20) & 0xF); + if (_month == 15) + _month = -1; + + _monthDay = (int)((packedTime >> 14) & 0x3F); + if (_monthDay == 63) + _monthDay = -1; + + _weekDay = (int)((packedTime >> 11) & 0x7); + if (_weekDay == 7) + _weekDay = -1; + + _hour = (int)((packedTime >> 6) & 0x1F); + if (_hour == 31) + _hour = -1; + + _minute = (int)(packedTime & 0x3F); + if (_minute == 63) + _minute = -1; + + _flags = (int)((packedTime >> 29) & 0x3); + if (_flags == 3) + _flags = -1; + } + + public long GetUnixTimeFromUtcTime() + { + if (_year < 0 || _month < 0 || _monthDay < 0) + return 0; + + return Time.DateTimeToUnixTime(new DateTime(_year + 100, _month, _monthDay + 1, _hour, _minute, 0, DateTimeKind.Utc)); + } + + public void SetUtcTimeFromUnixTime(long unixTime) + { + var dateTime = Time.UnixTimeToDateTime(unixTime); + + _year = (dateTime.Year - 100) % 100; + _month = dateTime.Month; + _monthDay = dateTime.Day - 1; + _weekDay = (int)dateTime.DayOfWeek; + _hour = dateTime.Hour; + _minute = dateTime.Minute; + } + + public bool IsInRange(WowTime from, WowTime to) + { + if (from.CompareTo(to) > 0) + return this >= from || this < to; + + return this >= from && this < to; + } + + public int GetYear() { return _year; } + public void SetYear(int year) + { + Cypher.Assert(year == -1 || (year >= 0 && year < 32)); + _year = year; + } + + public int GetMonth() { return _month; } + public void SetMonth(int month) + { + Cypher.Assert(month == -1 || (month >= 0 && month < 12)); + _month = month; + } + + public int GetMonthDay() { return _monthDay; } + public void SetMonthDay(int monthDay) + { + Cypher.Assert(monthDay == -1 || (monthDay >= 0 && monthDay < 32)); + _monthDay = monthDay; + } + + public int GetWeekDay() { return _weekDay; } + public void SetWeekDay(int weekDay) + { + Cypher.Assert(weekDay == -1 || (weekDay >= 0 && weekDay < 7)); + _weekDay = weekDay; + } + + public int GetHour() { return _hour; } + public void SetHour(int hour) + { + Cypher.Assert(hour == -1 || (hour >= 0 && hour < 24)); + _hour = hour; + } + + public int GetMinute() { return _minute; } + public void SetMinute(int minute) + { + Cypher.Assert(minute == -1 || (minute >= 0 && minute < 60)); + _minute = minute; + } + + public int GetFlags() { return _flags; } + public void SetFlags(int flags) + { + Cypher.Assert(flags == -1 || (flags >= 0 && flags < 3)); + _flags = flags; + } + + public int GetHolidayOffset() { return _holidayOffset; } + public void SetHolidayOffset(int holidayOffset) { _holidayOffset = holidayOffset; } + + public static WowTime operator +(WowTime time, TimeSpan seconds) + { + long unixTime = time.GetUnixTimeFromUtcTime(); + unixTime += (long)seconds.TotalSeconds; + time.SetUtcTimeFromUnixTime(unixTime); + return time; + } + + public static WowTime operator -(WowTime time, TimeSpan seconds) + { + long unixTime = time.GetUnixTimeFromUtcTime(); + unixTime -= (long)seconds.TotalSeconds; + time.SetUtcTimeFromUnixTime(unixTime); + return time; + } + + public void Write(WorldPacket data) + { + data.WriteUInt32(GetPackedTime()); + } + + public void Read(WorldPacket data) + { + uint packedTime = data.ReadPackedTime(); + SetPackedTime(packedTime); + } + + public int CompareTo(WowTime other) + { + var compareFieldIfSet = int (int left1, int right1) => + { + if (left1 < 0 || right1 < 0) + return 0; + + return left1.CompareTo(right1); + }; + + var cmp = compareFieldIfSet(_year, other._year); + if (cmp == -1) + return cmp; + + cmp = compareFieldIfSet(_month, other._month); + if (cmp == -1) + return cmp; + + cmp = compareFieldIfSet(_monthDay, other._monthDay); + if (cmp == -1) + return cmp; + + cmp = compareFieldIfSet(_weekDay, other._weekDay); + if (cmp == -1) + return cmp; + + cmp = compareFieldIfSet(_hour, other._hour); + if (cmp == -1) + return cmp; + + cmp = compareFieldIfSet(_minute, other._minute); + if (cmp == -1) + return cmp; + + return 0; + } + + public static bool operator >=(WowTime left, WowTime right) + { + return left.CompareTo(right) >= 0; + } + + public static bool operator <=(WowTime left, WowTime right) + { + return left.CompareTo(right) <= 0; + } + + public static bool operator >(WowTime left, WowTime right) + { + return left.CompareTo(right) > 0; + } + + public static bool operator <(WowTime left, WowTime right) + { + return left.CompareTo(right) < 0; + } + + public static bool operator ==(WowTime left, WowTime right) + { + return left.CompareTo(right) == 0; + } + + public static bool operator !=(WowTime left, WowTime right) + { + return left.CompareTo(right) != 0; + } +}