Core/Spells: Refactor SpellHistory ModifyCoooldowns and ResetCooldowns callbacks to use CooldownEntry argument instead of internal iterator

Port From (https://github.com/TrinityCore/TrinityCore/commit/ace6342aea9e8e3f69af88ca3963fc961ba56f1b)
This commit is contained in:
Hondacrx
2025-06-08 15:56:31 -04:00
parent 4ace6f58c6
commit a3a9ef5259
5 changed files with 87 additions and 84 deletions
+3 -3
View File
@@ -3378,13 +3378,13 @@ namespace Game.Entities
public void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns) public void RemoveArenaSpellCooldowns(bool removeActivePetCooldowns)
{ {
// remove cooldowns on spells that have < 10 min CD // remove cooldowns on spells that have < 10 min CD
GetSpellHistory().ResetCooldowns(p => GetSpellHistory().ResetCooldowns(cooldownEntry =>
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(p.Key, Difficulty.None); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cooldownEntry.SpellId, Difficulty.None);
TimeSpan cooldown = TimeSpan.Zero; TimeSpan cooldown = TimeSpan.Zero;
TimeSpan categoryCooldown = TimeSpan.Zero; TimeSpan categoryCooldown = TimeSpan.Zero;
uint categoryId = 0; uint categoryId = 0;
SpellHistory.GetCooldownDurations(spellInfo, p.Value.ItemId, ref cooldown, ref categoryId, ref categoryCooldown); SpellHistory.GetCooldownDurations(spellInfo, cooldownEntry.ItemId, ref cooldown, ref categoryId, ref categoryCooldown);
return cooldown < TimeSpan.FromMinutes(10) return cooldown < TimeSpan.FromMinutes(10)
&& categoryCooldown < TimeSpan.FromMinutes(10) && categoryCooldown < TimeSpan.FromMinutes(10)
&& !spellInfo.HasAttribute(SpellAttr6.DoNotResetCooldownInArena); && !spellInfo.HasAttribute(SpellAttr6.DoNotResetCooldownInArena);
+2 -2
View File
@@ -655,9 +655,9 @@ namespace Game.Entities
break; break;
} }
GetSpellHistory().ResetCooldowns(pair => GetSpellHistory().ResetCooldowns(cooldown =>
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(cooldown.SpellId, Difficulty.None);
return spellInfo.HasAttribute(SpellAttr10.ResetCooldownOnEncounterEnd); return spellInfo.HasAttribute(SpellAttr10.ResetCooldownOnEncounterEnd);
}, true); }, true);
} }
+3 -3
View File
@@ -5832,9 +5832,9 @@ namespace Game.Spells
if (effectHandleMode != SpellEffectHandleMode.HitTarget) if (effectHandleMode != SpellEffectHandleMode.HitTarget)
return; return;
unitTarget.GetSpellHistory().ModifyCoooldowns(itr => unitTarget.GetSpellHistory().ModifyCoooldowns(cooldown =>
{ {
SpellInfo spellOnCooldown = Global.SpellMgr.GetSpellInfo(itr.SpellId, Difficulty.None); SpellInfo spellOnCooldown = Global.SpellMgr.GetSpellInfo(cooldown.SpellId, Difficulty.None);
if ((int)spellOnCooldown.SpellFamilyName != effectInfo.MiscValue) if ((int)spellOnCooldown.SpellFamilyName != effectInfo.MiscValue)
return false; return false;
@@ -5854,7 +5854,7 @@ namespace Game.Spells
if (effectHandleMode != SpellEffectHandleMode.HitTarget) if (effectHandleMode != SpellEffectHandleMode.HitTarget)
return; return;
unitTarget.GetSpellHistory().ModifyCoooldowns(itr => Global.SpellMgr.GetSpellInfo(itr.SpellId, Difficulty.None).CategoryId == effectInfo.MiscValue, TimeSpan.FromMilliseconds(damage)); unitTarget.GetSpellHistory().ModifyCoooldowns(cooldown => Global.SpellMgr.GetSpellInfo(cooldown.SpellId, Difficulty.None).CategoryId == effectInfo.MiscValue, TimeSpan.FromMilliseconds(damage));
} }
[SpellEffectHandler(SpellEffectName.ModifyCharges)] [SpellEffectHandler(SpellEffectName.ModifyCharges)]
+76 -73
View File
@@ -84,29 +84,29 @@ namespace Game.Spells
trans.Append(stmt); trans.Append(stmt);
byte index; byte index;
foreach (var pair in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
if (!pair.Value.OnHold) if (!cooldown.OnHold)
{ {
index = 0; index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_PET_SPELL_COOLDOWN); stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_PET_SPELL_COOLDOWN);
stmt.AddValue(index++, _owner.GetCharmInfo().GetPetNumber()); stmt.AddValue(index++, _owner.GetCharmInfo().GetPetNumber());
stmt.AddValue(index++, pair.Key); stmt.AddValue(index++, spellId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.CooldownEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(cooldown.CooldownEnd));
stmt.AddValue(index++, pair.Value.CategoryId); stmt.AddValue(index++, cooldown.CategoryId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.CategoryEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(cooldown.CategoryEnd));
trans.Append(stmt); trans.Append(stmt);
} }
} }
foreach (var pair in _categoryCharges) foreach (var (categoryId, consumedCharges) in _categoryCharges)
{ {
index = 0; index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_PET_SPELL_CHARGES); stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_PET_SPELL_CHARGES);
stmt.AddValue(index++, _owner.GetCharmInfo().GetPetNumber()); stmt.AddValue(index++, _owner.GetCharmInfo().GetPetNumber());
stmt.AddValue(index++, pair.Key); stmt.AddValue(index++, categoryId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.RechargeStart)); stmt.AddValue(index++, Time.DateTimeToUnixTime(consumedCharges.RechargeStart));
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.RechargeEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(consumedCharges.RechargeEnd));
trans.Append(stmt); trans.Append(stmt);
} }
} }
@@ -121,30 +121,30 @@ namespace Game.Spells
trans.Append(stmt); trans.Append(stmt);
byte index; byte index;
foreach (var pair in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
if (!pair.Value.OnHold) if (!cooldown.OnHold)
{ {
index = 0; index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_CHAR_SPELL_COOLDOWN); stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_CHAR_SPELL_COOLDOWN);
stmt.AddValue(index++, _owner.GetGUID().GetCounter()); stmt.AddValue(index++, _owner.GetGUID().GetCounter());
stmt.AddValue(index++, pair.Key); stmt.AddValue(index++, spellId);
stmt.AddValue(index++, pair.Value.ItemId); stmt.AddValue(index++, cooldown.ItemId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.CooldownEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(cooldown.CooldownEnd));
stmt.AddValue(index++, pair.Value.CategoryId); stmt.AddValue(index++, cooldown.CategoryId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.CategoryEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(cooldown.CategoryEnd));
trans.Append(stmt); trans.Append(stmt);
} }
} }
foreach (var pair in _categoryCharges) foreach (var (categoryId, consumedCharges) in _categoryCharges)
{ {
index = 0; index = 0;
stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_CHAR_SPELL_CHARGES); stmt = CharacterDatabase.GetPreparedStatement(CharStatements.INS_CHAR_SPELL_CHARGES);
stmt.AddValue(index++, _owner.GetGUID().GetCounter()); stmt.AddValue(index++, _owner.GetGUID().GetCounter());
stmt.AddValue(index++, pair.Key); stmt.AddValue(index++, categoryId);
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.RechargeStart)); stmt.AddValue(index++, Time.DateTimeToUnixTime(consumedCharges.RechargeStart));
stmt.AddValue(index++, Time.DateTimeToUnixTime(pair.Value.RechargeEnd)); stmt.AddValue(index++, Time.DateTimeToUnixTime(consumedCharges.RechargeEnd));
trans.Append(stmt); trans.Append(stmt);
} }
} }
@@ -159,19 +159,19 @@ namespace Game.Spells
_categoryCooldowns.Remove(pair.Key); _categoryCooldowns.Remove(pair.Key);
} }
foreach (var pair in _spellCooldowns.ToList()) foreach (var (spellId, cooldown) in _spellCooldowns.ToList())
{ {
if (pair.Value.CooldownEnd < now) if (cooldown.CooldownEnd < now)
{ {
_categoryCooldowns.Remove(pair.Value.CategoryId); _categoryCooldowns.Remove(cooldown.CategoryId);
_spellCooldowns.Remove(pair.Key); _spellCooldowns.Remove(spellId);
} }
} }
foreach (var pair in _categoryCharges.KeyValueList) foreach (var (categoryId, consumedCharges) in _categoryCharges.KeyValueList)
{ {
if (pair.Value.RechargeEnd <= now) if (consumedCharges.RechargeEnd <= now)
_categoryCharges.Remove(pair); _categoryCharges.Remove(categoryId, consumedCharges);
} }
} }
@@ -230,24 +230,24 @@ namespace Game.Spells
public void WritePacket(SendSpellHistory sendSpellHistory) public void WritePacket(SendSpellHistory sendSpellHistory)
{ {
DateTime now = GameTime.GetSystemTime(); DateTime now = GameTime.GetSystemTime();
foreach (var p in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
SpellHistoryEntry historyEntry = new(); SpellHistoryEntry historyEntry = new();
historyEntry.SpellID = p.Key; historyEntry.SpellID = spellId;
historyEntry.ItemID = p.Value.ItemId; historyEntry.ItemID = cooldown.ItemId;
if (p.Value.OnHold) if (cooldown.OnHold)
historyEntry.OnHold = true; historyEntry.OnHold = true;
else else
{ {
TimeSpan cooldownDuration = p.Value.CooldownEnd - now; TimeSpan cooldownDuration = cooldown.CooldownEnd - now;
if (cooldownDuration.TotalMilliseconds <= 0) if (cooldownDuration.TotalMilliseconds <= 0)
continue; continue;
TimeSpan categoryDuration = p.Value.CategoryEnd - now; TimeSpan categoryDuration = cooldown.CategoryEnd - now;
if (categoryDuration.TotalMilliseconds > 0) if (categoryDuration.TotalMilliseconds > 0)
{ {
historyEntry.Category = p.Value.CategoryId; historyEntry.Category = cooldown.CategoryId;
historyEntry.CategoryRecoveryTime = (int)categoryDuration.TotalMilliseconds; historyEntry.CategoryRecoveryTime = (int)categoryDuration.TotalMilliseconds;
} }
@@ -262,19 +262,19 @@ namespace Game.Spells
public void WritePacket(SendSpellCharges sendSpellCharges) public void WritePacket(SendSpellCharges sendSpellCharges)
{ {
DateTime now = GameTime.GetSystemTime(); DateTime now = GameTime.GetSystemTime();
foreach (var key in _categoryCharges.Keys) foreach (var categoryId in _categoryCharges.Keys)
{ {
var list = _categoryCharges[key]; var consumedCharges = _categoryCharges[categoryId];
if (!list.Empty()) if (!consumedCharges.Empty())
{ {
TimeSpan cooldownDuration = list.FirstOrDefault().RechargeEnd - now; TimeSpan cooldownDuration = consumedCharges.FirstOrDefault().RechargeEnd - now;
if (cooldownDuration.TotalMilliseconds <= 0) if (cooldownDuration.TotalMilliseconds <= 0)
continue; continue;
SpellChargeEntry chargeEntry = new(); SpellChargeEntry chargeEntry = new();
chargeEntry.Category = key; chargeEntry.Category = categoryId;
chargeEntry.NextRecoveryTime = (uint)cooldownDuration.TotalMilliseconds; chargeEntry.NextRecoveryTime = (uint)cooldownDuration.TotalMilliseconds;
chargeEntry.ConsumedCharges = (byte)list.Count; chargeEntry.ConsumedCharges = (byte)consumedCharges.Count;
sendSpellCharges.Entries.Add(chargeEntry); sendSpellCharges.Entries.Add(chargeEntry);
} }
} }
@@ -284,20 +284,20 @@ namespace Game.Spells
{ {
DateTime now = GameTime.GetSystemTime(); DateTime now = GameTime.GetSystemTime();
foreach (var pair in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
PetSpellCooldown petSpellCooldown = new(); PetSpellCooldown petSpellCooldown = new();
petSpellCooldown.SpellID = pair.Key; petSpellCooldown.SpellID = spellId;
petSpellCooldown.Category = (ushort)pair.Value.CategoryId; petSpellCooldown.Category = (ushort)cooldown.CategoryId;
if (!pair.Value.OnHold) if (!cooldown.OnHold)
{ {
var cooldownDuration = pair.Value.CooldownEnd - now; var cooldownDuration = cooldown.CooldownEnd - now;
if (cooldownDuration.TotalMilliseconds <= 0) if (cooldownDuration.TotalMilliseconds <= 0)
continue; continue;
petSpellCooldown.Duration = (uint)cooldownDuration.TotalMilliseconds; petSpellCooldown.Duration = (uint)cooldownDuration.TotalMilliseconds;
var categoryDuration = pair.Value.CategoryEnd - now; var categoryDuration = cooldown.CategoryEnd - now;
if (categoryDuration.TotalMilliseconds > 0) if (categoryDuration.TotalMilliseconds > 0)
petSpellCooldown.CategoryDuration = (uint)categoryDuration.TotalMilliseconds; petSpellCooldown.CategoryDuration = (uint)categoryDuration.TotalMilliseconds;
} }
@@ -307,19 +307,19 @@ namespace Game.Spells
petSpells.Cooldowns.Add(petSpellCooldown); petSpells.Cooldowns.Add(petSpellCooldown);
} }
foreach (var key in _categoryCharges.Keys) foreach (var categoryId in _categoryCharges.Keys)
{ {
var list = _categoryCharges[key]; var consumedCharges = _categoryCharges[categoryId];
if (!list.Empty()) if (!consumedCharges.Empty())
{ {
var cooldownDuration = list.FirstOrDefault().RechargeEnd - now; var cooldownDuration = consumedCharges.FirstOrDefault().RechargeEnd - now;
if (cooldownDuration.TotalMilliseconds <= 0) if (cooldownDuration.TotalMilliseconds <= 0)
continue; continue;
PetSpellHistory petChargeEntry = new(); PetSpellHistory petChargeEntry = new();
petChargeEntry.CategoryID = key; petChargeEntry.CategoryID = categoryId;
petChargeEntry.RecoveryTime = (uint)cooldownDuration.TotalMilliseconds; petChargeEntry.RecoveryTime = (uint)cooldownDuration.TotalMilliseconds;
petChargeEntry.ConsumedCharges = (sbyte)list.Count; petChargeEntry.ConsumedCharges = (sbyte)consumedCharges.Count;
petSpells.SpellHistory.Add(petChargeEntry); petSpells.SpellHistory.Add(petChargeEntry);
} }
@@ -596,12 +596,12 @@ namespace Game.Spells
_spellCooldowns.Remove(spellId); _spellCooldowns.Remove(spellId);
} }
public void ResetCooldowns(Func<KeyValuePair<uint, CooldownEntry>, bool> predicate, bool update = false) public void ResetCooldowns(Func<CooldownEntry, bool> predicate, bool update = false)
{ {
List<uint> resetCooldowns = new(); List<uint> resetCooldowns = new();
foreach (var pair in _spellCooldowns) foreach (var pair in _spellCooldowns)
{ {
if (predicate(pair)) if (predicate(pair.Value))
{ {
resetCooldowns.Add(pair.Key); resetCooldowns.Add(pair.Key);
ResetCooldown(pair.Key, false); ResetCooldown(pair.Key, false);
@@ -681,12 +681,11 @@ namespace Game.Spells
public TimeSpan GetRemainingCategoryCooldown(uint categoryId) public TimeSpan GetRemainingCategoryCooldown(uint categoryId)
{ {
DateTime end;
var cooldownEntry = _categoryCooldowns.LookupByKey(categoryId); var cooldownEntry = _categoryCooldowns.LookupByKey(categoryId);
if (cooldownEntry == null) if (cooldownEntry == null)
return TimeSpan.Zero; return TimeSpan.Zero;
end = cooldownEntry.CategoryEnd; DateTime end = cooldownEntry.CategoryEnd;
DateTime now = GameTime.GetSystemTime(); DateTime now = GameTime.GetSystemTime();
if (end < now) if (end < now)
@@ -713,16 +712,16 @@ namespace Game.Spells
Player plrOwner = _owner.ToPlayer(); Player plrOwner = _owner.ToPlayer();
if (plrOwner != null) if (plrOwner != null)
{ {
foreach (var p in plrOwner.GetSpellMap()) foreach (var (spellId, playerSpell) in plrOwner.GetSpellMap())
if (p.Value.State != PlayerSpellState.Removed) if (playerSpell.State != PlayerSpellState.Removed)
knownSpells.Add(p.Key); knownSpells.Add(spellId);
} }
else if (_owner.IsPet()) else if (_owner.IsPet())
{ {
Pet petOwner = _owner.ToPet(); Pet petOwner = _owner.ToPet();
foreach (var p in petOwner.m_spells) foreach (var (spellId, petSpell) in petOwner.m_spells)
if (p.Value.state != PetSpellState.Removed) if (petSpell.state != PetSpellState.Removed)
knownSpells.Add(p.Key); knownSpells.Add(spellId);
} }
else else
{ {
@@ -1057,19 +1056,23 @@ namespace Game.Spells
if (player != null) if (player != null)
{ {
// add all profession CDs created while in duel (if any) // add all profession CDs created while in duel (if any)
foreach (var c in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(c.Key, Difficulty.None); SpellInfo spellInfo = Global.SpellMgr.GetSpellInfo(spellId, Difficulty.None);
if (spellInfo.RecoveryTime > 10 * Time.Minute * Time.InMilliseconds || spellInfo.CategoryRecoveryTime > 10 * Time.Minute * Time.InMilliseconds) if (spellInfo.RecoveryTime > 10 * Time.Minute * Time.InMilliseconds || spellInfo.CategoryRecoveryTime > 10 * Time.Minute * Time.InMilliseconds)
_spellCooldownsBeforeDuel[c.Key] = _spellCooldowns[c.Key]; _spellCooldownsBeforeDuel[spellId] = cooldown;
} }
// check for spell with onHold active before and during the duel // check for spell with onHold active before and during the duel
foreach (var pair in _spellCooldownsBeforeDuel) foreach (var (spellId, cooldown) in _spellCooldownsBeforeDuel)
{ {
if (!pair.Value.OnHold && _spellCooldowns.ContainsKey(pair.Key) && !_spellCooldowns[pair.Key].OnHold) if (cooldown.OnHold)
_spellCooldowns[pair.Key] = _spellCooldownsBeforeDuel[pair.Key]; continue;
var inserted = _spellCooldowns.TryAdd(spellId, cooldown);
if (!inserted && !_spellCooldowns[spellId].OnHold /*don't override if pre-existing cooldown is on hold*/)
_spellCooldowns[spellId] = cooldown;
} }
// update the client: restore old cooldowns // update the client: restore old cooldowns
@@ -1077,16 +1080,16 @@ namespace Game.Spells
spellCooldown.Caster = _owner.GetGUID(); spellCooldown.Caster = _owner.GetGUID();
spellCooldown.Flags = SpellCooldownFlags.IncludeEventCooldowns; spellCooldown.Flags = SpellCooldownFlags.IncludeEventCooldowns;
foreach (var c in _spellCooldowns) foreach (var (spellId, cooldown) in _spellCooldowns)
{ {
DateTime now = GameTime.GetSystemTime(); DateTime now = GameTime.GetSystemTime();
uint cooldownDuration = c.Value.CooldownEnd > now ? (uint)(c.Value.CooldownEnd - now).TotalMilliseconds : 0; uint cooldownDuration = cooldown.CooldownEnd > now ? (uint)(cooldown.CooldownEnd - now).TotalMilliseconds : 0;
// cooldownDuration must be between 0 and 10 minutes in order to avoid any visual bugs // cooldownDuration must be between 0 and 10 minutes in order to avoid any visual bugs
if (cooldownDuration <= 0 || cooldownDuration > 10 * Time.Minute * Time.InMilliseconds || c.Value.OnHold) if (cooldownDuration <= 0 || cooldownDuration > 10 * Time.Minute * Time.InMilliseconds || cooldown.OnHold)
continue; continue;
spellCooldown.SpellCooldowns.Add(new SpellCooldownStruct(c.Key, cooldownDuration)); spellCooldown.SpellCooldowns.Add(new SpellCooldownStruct(spellId, cooldownDuration));
} }
player.SendPacket(spellCooldown); player.SendPacket(spellCooldown);
+3 -3
View File
@@ -78,9 +78,9 @@ namespace Scripts.World.DuelReset
static void ResetSpellCooldowns(Player player, bool onStartDuel) static void ResetSpellCooldowns(Player player, bool onStartDuel)
{ {
// Remove cooldowns on spells that have < 10 min Cd > 30 sec and has no onHold // Remove cooldowns on spells that have < 10 min Cd > 30 sec and has no onHold
player.GetSpellHistory().ResetCooldowns(pair => player.GetSpellHistory().ResetCooldowns(cooldown =>
{ {
SpellInfo spellInfo = SpellMgr.GetSpellInfo(pair.Key, Difficulty.None); SpellInfo spellInfo = SpellMgr.GetSpellInfo(cooldown.SpellId, Difficulty.None);
TimeSpan remainingCooldown = player.GetSpellHistory().GetRemainingCooldown(spellInfo); TimeSpan remainingCooldown = player.GetSpellHistory().GetRemainingCooldown(spellInfo);
TimeSpan totalCooldown = TimeSpan.FromMilliseconds(spellInfo.RecoveryTime); TimeSpan totalCooldown = TimeSpan.FromMilliseconds(spellInfo.RecoveryTime);
TimeSpan categoryCooldown = TimeSpan.FromMilliseconds(spellInfo.CategoryRecoveryTime); TimeSpan categoryCooldown = TimeSpan.FromMilliseconds(spellInfo.CategoryRecoveryTime);
@@ -102,7 +102,7 @@ namespace Scripts.World.DuelReset
applySpellMod(categoryCooldown); applySpellMod(categoryCooldown);
return remainingCooldown > TimeSpan.FromMilliseconds(0) return remainingCooldown > TimeSpan.FromMilliseconds(0)
&& !pair.Value.OnHold && !cooldown.OnHold
&& totalCooldown < TimeSpan.FromMinutes(10) && totalCooldown < TimeSpan.FromMinutes(10)
&& categoryCooldown < TimeSpan.FromMinutes(10) && categoryCooldown < TimeSpan.FromMinutes(10)
&& remainingCooldown < TimeSpan.FromMinutes(10) && remainingCooldown < TimeSpan.FromMinutes(10)