From 4b08dc27564bfc8cae72ae12a585ccd0af736fe1 Mon Sep 17 00:00:00 2001 From: hondacrx Date: Tue, 4 Jan 2022 20:40:30 -0500 Subject: [PATCH] Core/Calendar: Add some additional validation when creating events Port From (https://github.com/TrinityCore/TrinityCore/commit/562c567b1e0c878f0632994a79bcfbfd4a962504) --- Source/Framework/Constants/SharedConst.cs | 16 +++- Source/Game/Calendar/CalendarManager.cs | 97 +++++++++++++++++------ Source/Game/Handlers/CalendarHandler.cs | 92 +++++++++++++++++++-- Source/Game/Server/WorldManager.cs | 35 +++++++- Source/Game/Server/WorldSession.cs | 7 ++ Source/WorldServer/WorldServer.conf.dist | 8 ++ 6 files changed, 222 insertions(+), 33 deletions(-) diff --git a/Source/Framework/Constants/SharedConst.cs b/Source/Framework/Constants/SharedConst.cs index f043a3ad9..9c0ba2e31 100644 --- a/Source/Framework/Constants/SharedConst.cs +++ b/Source/Framework/Constants/SharedConst.cs @@ -142,11 +142,19 @@ namespace Framework.Constants public const uint VoidStorageMaxWithdraw = 9; public const byte VoidStorageMaxSlot = 160; + /// + /// Calendar Const + /// + public const uint CalendarMaxEvents = 30; + public const uint CalendarMaxGuildEvents = 100; + public const uint CalendarMaxInvites = 100; + public const uint CalendarCreateEventCooldown = 5; + public const uint CalendarOldEventsDeletionTime = 1 * Time.Month; + public const uint CalendarDefaultResponseTime = 946684800; // 01/01/2000 00:00:00 + /// /// Misc Const /// - public const uint CalendarMaxInvites = 100; - public const uint CalendarDefaultResponseTime = 946684800; // 01/01/2000 00:00:00 public const Locale DefaultLocale = Locale.enUS; public const int MaxAccountTutorialValues = 8; public const int MinAuctionTime = (12 * Time.Hour); @@ -892,7 +900,8 @@ namespace Framework.Constants CleaningFlags = 20004, // Cleaning Flags GuildDailyResetTime = 20006, // Next guild cap reset time MonthlyQuestResetTime = 20007, // Next monthly quest reset time - DailyQuestResetTime = 2008, // Next daily quest reset time + DailyQuestResetTime = 20008, // Next daily quest reset time + DailyCalendarDeletionOldEventsTime = 20009, // Next daily calendar deletions of old events time // Cata specific custom worldstates GuildWeeklyResetTime = 20050, // Next guild week reset time } @@ -1427,6 +1436,7 @@ namespace Framework.Constants CacheDataQueries, CalculateCreatureZoneAreaData, CalculateGameobjectZoneAreaData, + CalendarDeleteOldEventsHour, CastUnstuck, CharacterCreatingDisableAlliedRaceAchievementRequirement, CharacterCreatingDisabled, diff --git a/Source/Game/Calendar/CalendarManager.cs b/Source/Game/Calendar/CalendarManager.cs index f7cd10b6c..492901337 100644 --- a/Source/Game/Calendar/CalendarManager.cs +++ b/Source/Game/Calendar/CalendarManager.cs @@ -146,13 +146,24 @@ namespace Game return; } + RemoveEvent(calendarEvent, remover); + } + + void RemoveEvent(CalendarEvent calendarEvent, ObjectGuid remover) + { + if (calendarEvent == null) + { + SendCalendarCommandResult(remover, CalendarError.EventInvalid); + return; + } + SendCalendarEventRemovedAlert(calendarEvent); SQLTransaction trans = new(); PreparedStatement stmt; MailDraft mail = new(calendarEvent.BuildCalendarMailSubject(remover), calendarEvent.BuildCalendarMailBody()); - var eventInvites = _invites[eventId]; + var eventInvites = _invites[calendarEvent.EventId]; for (int i = 0; i < eventInvites.Count; ++i) { CalendarInvite invite = eventInvites[i]; @@ -166,10 +177,10 @@ namespace Game mail.SendMailTo(trans, new MailReceiver(invite.InviteeGuid.GetCounter()), new MailSender(calendarEvent), MailCheckMask.Copied); } - _invites.Remove(eventId); + _invites.Remove(calendarEvent.EventId); stmt = DB.Characters.GetPreparedStatement(CharStatements.DEL_CALENDAR_EVENT); - stmt.AddValue(0, eventId); + stmt.AddValue(0, calendarEvent.EventId); trans.Append(stmt); DB.Characters.CommitTransaction(trans); @@ -329,6 +340,42 @@ namespace Game return inviteId; } + public void DeleteOldEvents() + { + long oldEventsTime = GameTime.GetGameTime() - SharedConst.CalendarOldEventsDeletionTime; + + foreach (var calendarEvent in _events) + { + if (calendarEvent.Date < oldEventsTime) + RemoveEvent(calendarEvent, ObjectGuid.Empty); + } + } + + public List GetEventsCreatedBy(ObjectGuid guid, bool includeGuildEvents = false) + { + List result = new(); + foreach (var calendarEvent in _events) + if (calendarEvent.OwnerGuid == guid && (includeGuildEvents || (!calendarEvent.IsGuildEvent() && !calendarEvent.IsGuildAnnouncement()))) + result.Add(calendarEvent); + + return result; + } + + public List GetGuildEvents(ulong guildId) + { + List result = new(); + + if (guildId == 0) + return result; + + foreach (var calendarEvent in _events) + if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) + if (calendarEvent.GuildId == guildId) + result.Add(calendarEvent); + + return result; + } + public List GetPlayerEvents(ObjectGuid guid) { List events = new(); @@ -342,8 +389,9 @@ namespace Game events.Add(Event); } } + Player player = Global.ObjAccessor.FindPlayer(guid); - if (player) + if (player?.GetGuildId() != 0) { foreach (var calendarEvent in _events) if (calendarEvent.GuildId == player.GetGuildId()) @@ -643,6 +691,15 @@ namespace Game public class CalendarInvite { + public ulong InviteId { get; set; } + public ulong EventId { get; set; } + public ObjectGuid InviteeGuid { get; set; } + public ObjectGuid SenderGuid { get; set; } + public long ResponseTime { get; set; } + public CalendarInviteStatus Status { get; set; } + public CalendarModerationRank Rank { get; set; } + public string Note { get; set; } + public CalendarInvite() { InviteId = 1; @@ -680,19 +737,21 @@ namespace Game if (InviteId != 0 && EventId != 0) Global.CalendarMgr.FreeInviteId(InviteId); } - - public ulong InviteId { get; set; } - public ulong EventId { get; set; } - public ObjectGuid InviteeGuid { get; set; } - public ObjectGuid SenderGuid { get; set; } - public long ResponseTime { get; set; } - public CalendarInviteStatus Status { get; set; } - public CalendarModerationRank Rank { get; set; } - public string Note { get; set; } } public class CalendarEvent { + public ulong EventId { get; set; } + public ObjectGuid OwnerGuid { get; set; } + public ulong GuildId { get; set; } + public CalendarEventType EventType { get; set; } + public int TextureId { get; set; } + public long Date { get; set; } + public CalendarFlags Flags { get; set; } + public string Title { get; set; } + public string Description { get; set; } + public long LockDate { get; set; } + public CalendarEvent(CalendarEvent calendarEvent, ulong eventId) { EventId = eventId; @@ -746,15 +805,7 @@ namespace Game public bool IsGuildAnnouncement() { return Flags.HasAnyFlag(CalendarFlags.WithoutInvites); } public bool IsLocked() { return Flags.HasAnyFlag(CalendarFlags.InvitesLocked); } - public ulong EventId { get; set; } - public ObjectGuid OwnerGuid { get; set; } - public ulong GuildId { get; set; } - public CalendarEventType EventType { get; set; } - public int TextureId { get; set; } - public long Date { get; set; } - public CalendarFlags Flags { get; set; } - public string Title { get; set; } - public string Description { get; set; } - public long LockDate { get; set; } + public static bool IsGuildEvent(uint flags) { return (flags & (uint)CalendarFlags.GuildEvent) != 0; } + public static bool IsGuildAnnouncement(uint flags) { return (flags & (uint)CalendarFlags.WithoutInvites) != 0; } } } diff --git a/Source/Game/Handlers/CalendarHandler.cs b/Source/Game/Handlers/CalendarHandler.cs index 5a70bc906..3caf5b56d 100644 --- a/Source/Game/Handlers/CalendarHandler.cs +++ b/Source/Game/Handlers/CalendarHandler.cs @@ -124,17 +124,51 @@ namespace Game // prevent events in the past // To Do: properly handle timezones and remove the "- time_t(86400L)" hack if (calendarAddEvent.EventInfo.Time < (GameTime.GetGameTime() - 86400L)) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventPassed); return; + } + + // If the event is a guild event, check if the player is in a guild + if (CalendarEvent.IsGuildEvent(calendarAddEvent.EventInfo.Flags) || CalendarEvent.IsGuildAnnouncement(calendarAddEvent.EventInfo.Flags)) + { + if (_player.GetGuildId() == 0) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.GuildPlayerNotInGuild); + return; + } + } + + // Check if the player reached the max number of events allowed to create + if (CalendarEvent.IsGuildEvent(calendarAddEvent.EventInfo.Flags) || CalendarEvent.IsGuildAnnouncement(calendarAddEvent.EventInfo.Flags)) + { + if (Global.CalendarMgr.GetGuildEvents(_player.GetGuildId()).Count >= SharedConst.CalendarMaxGuildEvents) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.GuildEventsExceeded); + return; + } + } + else + { + if (Global.CalendarMgr.GetEventsCreatedBy(guid).Count >= SharedConst.CalendarMaxEvents) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventsExceeded); + return; + } + } + + if (GetCalendarEventCreationCooldown() > GameTime.GetGameTime()) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.Internal); + return; + } + 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); if (calendarEvent.IsGuildEvent() || calendarEvent.IsGuildAnnouncement()) - { - Player creator = Global.ObjAccessor.FindPlayer(guid); - if (creator) - calendarEvent.GuildId = creator.GetGuildId(); - } + calendarEvent.GuildId = _player.GetGuildId(); if (calendarEvent.IsGuildAnnouncement()) { @@ -209,11 +243,57 @@ namespace Game // prevent events in the past // To Do: properly handle timezones and remove the "- time_t(86400L)" hack if (calendarCopyEvent.Date < (GameTime.GetGameTime() - 86400L)) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventPassed); return; - + } + CalendarEvent oldEvent = Global.CalendarMgr.GetEvent(calendarCopyEvent.EventID); if (oldEvent != null) { + // Ensure that the player has access to the event + if (oldEvent.IsGuildEvent() || oldEvent.IsGuildAnnouncement()) + { + if (oldEvent.GuildId != _player.GetGuildId()) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid); + return; + } + } + else + { + if (oldEvent.OwnerGuid != guid) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventInvalid); + return; + } + } + + // Check if the player reached the max number of events allowed to create + if (oldEvent.IsGuildEvent() || oldEvent.IsGuildAnnouncement()) + { + if (Global.CalendarMgr.GetGuildEvents(_player.GetGuildId()).Count >= SharedConst.CalendarMaxGuildEvents) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.GuildEventsExceeded); + return; + } + } + else + { + if (Global.CalendarMgr.GetEventsCreatedBy(guid).Count >= SharedConst.CalendarMaxEvents) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.EventsExceeded); + return; + } + } + + if (GetCalendarEventCreationCooldown() > GameTime.GetGameTime()) + { + Global.CalendarMgr.SendCalendarCommandResult(guid, CalendarError.Internal); + return; + } + SetCalendarEventCreationCooldown(GameTime.GetGameTime() + SharedConst.CalendarCreateEventCooldown); + CalendarEvent newEvent = new(oldEvent, Global.CalendarMgr.GetFreeEventId()); newEvent.Date = calendarCopyEvent.Date; Global.CalendarMgr.AddEvent(newEvent, CalendarSendEventType.Copy); diff --git a/Source/Game/Server/WorldManager.cs b/Source/Game/Server/WorldManager.cs index f4f0d7424..f01f42f9a 100644 --- a/Source/Game/Server/WorldManager.cs +++ b/Source/Game/Server/WorldManager.cs @@ -1072,9 +1072,12 @@ namespace Game InitQuestResetTimes(); CheckScheduledResetTimes(); - Log.outInfo(LogFilter.ServerLoading, "Calculate random Battlegroundreset time..."); + Log.outInfo(LogFilter.ServerLoading, "Calculate random battleground reset time..."); InitRandomBGResetTime(); + Log.outInfo(LogFilter.ServerLoading, "Calculate deletion of old calendar events time..."); + InitCalendarOldEventsDeletionTime(); + Log.outInfo(LogFilter.ServerLoading, "Calculate Guild cap reset time..."); InitGuildResetTime(); @@ -1310,6 +1313,9 @@ namespace Game if (currentGameTime > m_NextRandomBGReset) ResetRandomBG(); + if (currentGameTime > m_NextCalendarOldEventsDeletionTime) + CalendarDeleteOldEvents(); + if (currentGameTime > m_NextGuildReset) ResetGuildCap(); @@ -2114,6 +2120,23 @@ namespace Game SetWorldState(WorldStates.BGDailyResetTime, (ulong)m_NextRandomBGReset); } + void InitCalendarOldEventsDeletionTime() + { + long now = GameTime.GetGameTime(); + long nextDeletionTime = Time.GetLocalHourTimestamp(now, WorldConfig.GetUIntValue(WorldCfg.CalendarDeleteOldEventsHour)); + long currentDeletionTime = GetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime); + + // If the reset time saved in the worldstate is before now it means the server was offline when the reset was supposed to occur. + // In this case we set the reset time in the past and next world update will do the reset and schedule next one in the future. + if (currentDeletionTime < now) + m_NextCalendarOldEventsDeletionTime = nextDeletionTime - Time.Day; + else + m_NextCalendarOldEventsDeletionTime = nextDeletionTime; + + if (currentDeletionTime == 0) + SetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime, (ulong)m_NextCalendarOldEventsDeletionTime); + } + void InitGuildResetTime() { long gtime = GetWorldState(WorldStates.GuildDailyResetTime); @@ -2193,6 +2216,15 @@ namespace Game SetWorldState(WorldStates.BGDailyResetTime, (ulong)m_NextRandomBGReset); } + void CalendarDeleteOldEvents() + { + Log.outInfo(LogFilter.Misc, "Calendar deletion of old events."); + + m_NextCalendarOldEventsDeletionTime = m_NextCalendarOldEventsDeletionTime + Time.Day; + SetWorldState(WorldStates.DailyCalendarDeletionOldEventsTime, (ulong)m_NextCalendarOldEventsDeletionTime); + Global.CalendarMgr.DeleteOldEvents(); + } + void ResetGuildCap() { m_NextGuildReset += Time.Day; @@ -2489,6 +2521,7 @@ namespace Game long m_NextWeeklyQuestReset; long m_NextMonthlyQuestReset; long m_NextRandomBGReset; + long m_NextCalendarOldEventsDeletionTime; long m_NextGuildReset; long m_NextCurrencyReset; diff --git a/Source/Game/Server/WorldSession.cs b/Source/Game/Server/WorldSession.cs index f98153c17..681a755b1 100644 --- a/Source/Game/Server/WorldSession.cs +++ b/Source/Game/Server/WorldSession.cs @@ -890,6 +890,10 @@ namespace Game public uint GetRecruiterId() { return recruiterId; } public bool IsARecruiter() { return isRecruiter; } + // Packets cooldown + public long GetCalendarEventCreationCooldown() { return _calendarEventCreationCooldown; } + public void SetCalendarEventCreationCooldown(long cooldown) { _calendarEventCreationCooldown = cooldown; } + // Battle Pets public BattlePetMgr GetBattlePetMgr() { return _battlePetMgr; } public CollectionMgr GetCollectionMgr() { return _collectionMgr; } @@ -967,6 +971,9 @@ namespace Game ConnectToKey _instanceConnectKey; + // Packets cooldown + long _calendarEventCreationCooldown; + BattlePetMgr _battlePetMgr; Task> _realmAccountLoginCallback; diff --git a/Source/WorldServer/WorldServer.conf.dist b/Source/WorldServer/WorldServer.conf.dist index 6f519c409..dd0885cd5 100644 --- a/Source/WorldServer/WorldServer.conf.dist +++ b/Source/WorldServer/WorldServer.conf.dist @@ -1034,6 +1034,14 @@ Quests.DailyResetTime = 3 Quests.WeeklyResetWDay = 3 +# +# Calendar.DeleteOldEventsHour +# Description: Hour of the day when the daily deletion of old calendar events occurs. +# Range: 0-23 +# Default: 6 - (06:00 AM) + +Calendar.DeleteOldEventsHour = 6 + # # Guild.EventLogRecordsCount # Description: Number of log entries for guild events that are stored per guild. Old entries