From 7b6cf66b87ae79dba814612a8394276a9865dfe0 Mon Sep 17 00:00:00 2001 From: Mark Sturgill Date: Mon, 7 Oct 2013 00:22:11 -0700 Subject: [PATCH] rework Core.TickCount --- Scripts/Items/Maps/TreasureMap.cs | 8 ++-- Scripts/Mobiles/AI/BaseAI.cs | 8 ++-- Scripts/Mobiles/AI/MageAI.cs | 4 +- Scripts/Mobiles/BaseCreature.cs | 16 +++---- Scripts/Mobiles/PlayerMobile.cs | 6 +-- Scripts/Spells/Base/Spell.cs | 4 +- Server/Main.cs | 74 +++++++++++++++++++++++++++---- Server/Mobile.cs | 34 +++++++------- Server/Network/NetState.cs | 2 +- 9 files changed, 107 insertions(+), 49 deletions(-) diff --git a/Scripts/Items/Maps/TreasureMap.cs b/Scripts/Items/Maps/TreasureMap.cs index b074248dc..1ac465d29 100644 --- a/Scripts/Items/Maps/TreasureMap.cs +++ b/Scripts/Items/Maps/TreasureMap.cs @@ -444,10 +444,10 @@ namespace Server.Items private int m_Count; - private int m_NextSkillTime; - private int m_NextSpellTime; - private int m_NextActionTime; - private int m_LastMoveTime; + private long m_NextSkillTime; + private long m_NextSpellTime; + private long m_NextActionTime; + private long m_LastMoveTime; public DigTimer( Mobile from, TreasureMap treasureMap, Point3D location, Map map ) : base( TimeSpan.Zero, TimeSpan.FromSeconds( 1.0 ) ) { diff --git a/Scripts/Mobiles/AI/BaseAI.cs b/Scripts/Mobiles/AI/BaseAI.cs index 2f7298e1a..48793bc06 100644 --- a/Scripts/Mobiles/AI/BaseAI.cs +++ b/Scripts/Mobiles/AI/BaseAI.cs @@ -45,7 +45,7 @@ namespace Server.Mobiles { public Timer m_Timer; protected ActionType m_Action; - private int m_NextStopGuard; + private long m_NextStopGuard; public BaseCreature m_Mobile; @@ -1999,9 +1999,9 @@ namespace Server.Mobiles return delay; } - private int m_NextMove; + private long m_NextMove; - public int NextMove + public long NextMove { get { return m_NextMove; } set { m_NextMove = value; } @@ -2718,7 +2718,7 @@ namespace Server.Mobiles m_Timer.Start(); } - private int m_NextDetectHidden; + private long m_NextDetectHidden; public virtual bool CanDetectHidden { get { return m_Mobile.Skills[SkillName.DetectHidden].Value > 0; } } diff --git a/Scripts/Mobiles/AI/MageAI.cs b/Scripts/Mobiles/AI/MageAI.cs index 14dc3c651..b71204aca 100644 --- a/Scripts/Mobiles/AI/MageAI.cs +++ b/Scripts/Mobiles/AI/MageAI.cs @@ -15,8 +15,8 @@ namespace Server.Mobiles { public class MageAI : BaseAI { - private int m_NextCastTime; - private int m_NextHealTime; + private long m_NextCastTime; + private long m_NextHealTime; public MageAI( BaseCreature m ) : base( m ) diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs index 57e91dc77..c3d620f42 100644 --- a/Scripts/Mobiles/BaseCreature.cs +++ b/Scripts/Mobiles/BaseCreature.cs @@ -616,7 +616,7 @@ namespace Server.Mobiles public virtual bool DisplayWeight{ get{ return Backpack is StrongBackpack; } } #region Breath ability, like dragon fire breath - private int m_NextBreathTime; + private long m_NextBreathTime; // Must be overriden in subclass to enable public virtual bool HasBreath{ get{ return false; } } @@ -4962,9 +4962,9 @@ namespace Server.Mobiles * This functionality appears to be implemented on OSI as well */ - private int m_NextReacquireTime; + private long m_NextReacquireTime; - public int NextReacquireTime{ get{ return m_NextReacquireTime; } set{ m_NextReacquireTime = value; } } + public long NextReacquireTime { get { return m_NextReacquireTime; } set { m_NextReacquireTime = value; } } public virtual TimeSpan ReacquireDelay{ get{ return TimeSpan.FromSeconds( 10.0 ); } } public virtual bool ReacquireOnMovement{ get{ return false; } } @@ -5152,7 +5152,7 @@ namespace Server.Mobiles private const double MinutesToNextChanceMin = 0.25; private const double MinutesToNextChanceMax = 0.75; - private int m_NextRummageTime; + private long m_NextRummageTime; public virtual bool CanBreath { get { return HasBreath && !Summoned; } } public virtual bool IsDispellable { get { return Summoned && !IsAnimatedDead; } } @@ -5174,8 +5174,8 @@ namespace Server.Mobiles public virtual double HealOwnerInterval { get { return 30.0; } } public virtual bool HealOwnerFully { get { return false; } } - private int m_NextHealTime = Core.TickCount; - private int m_NextHealOwnerTime = Core.TickCount; + private long m_NextHealTime = Core.TickCount; + private long m_NextHealOwnerTime = Core.TickCount; private Timer m_HealTimer = null; public bool IsHealing { get { return ( m_HealTimer != null ); } } @@ -5292,7 +5292,7 @@ namespace Server.Mobiles #endregion #region Damaging Aura - private int m_NextAura; + private long m_NextAura; public virtual bool HasAura { get { return false; } } public virtual TimeSpan AuraInterval { get { return TimeSpan.FromSeconds( 5 ); } } @@ -5345,7 +5345,7 @@ namespace Server.Mobiles public virtual void OnThink() { - int tc = Core.TickCount; + long tc = Core.TickCount; if ( EnableRummaging && CanRummageCorpses && !Summoned && !Controlled && tc - m_NextRummageTime >= 0 ) { diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index 30c61ab02..48189900e 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -261,7 +261,7 @@ namespace Server.Mobiles } [CommandProperty( AccessLevel.GameMaster )] - public int LastMoved + public long LastMoved { get{ return LastMoveTime; } } @@ -4073,7 +4073,7 @@ namespace Server.Mobiles private static bool FastwalkPrevention = true; // Is fastwalk prevention enabled? private static int FastwalkThreshold = 400; // Fastwalk prevention will become active after 0.4 seconds - private int m_NextMovementTime; + private long m_NextMovementTime; private bool m_HasMoved; public virtual bool UsesFastwalkPrevention{ get{ return ( AccessLevel < AccessLevel.Counselor ); } } @@ -4115,7 +4115,7 @@ namespace Server.Mobiles return true; } - int ts = pm.m_NextMovementTime - Core.TickCount; + long ts = pm.m_NextMovementTime - Core.TickCount; if ( ts < 0 ) { diff --git a/Scripts/Spells/Base/Spell.cs b/Scripts/Spells/Base/Spell.cs index ddedd4f0e..440b49b12 100644 --- a/Scripts/Spells/Base/Spell.cs +++ b/Scripts/Spells/Base/Spell.cs @@ -18,7 +18,7 @@ namespace Server.Spells private Item m_Scroll; private SpellInfo m_Info; private SpellState m_State; - private int m_StartCastTime; + private long m_StartCastTime; public SpellState State{ get{ return m_State; } set{ m_State = value; } } public Mobile Caster{ get{ return m_Caster; } } @@ -27,7 +27,7 @@ namespace Server.Spells public string Mantra{ get{ return m_Info.Mantra; } } public Type[] Reagents{ get{ return m_Info.Reagents; } } public Item Scroll{ get{ return m_Scroll; } } - public int StartCastTime { get { return m_StartCastTime; } } + public long StartCastTime { get { return m_StartCastTime; } } private static TimeSpan NextSpellDelay = TimeSpan.FromSeconds( 0.75 ); private static TimeSpan AnimateDelay = TimeSpan.FromSeconds( 1.5 ); diff --git a/Server/Main.cs b/Server/Main.cs index ffe43e0dd..f110a64a2 100644 --- a/Server/Main.cs +++ b/Server/Main.cs @@ -112,13 +112,71 @@ namespace Server public static Thread Thread { get { return m_Thread; } } public static MultiTextWriter MultiConsoleOut { get { return m_MultiConOut; } } - public static int TickCount { +#if false && !MONO + [DllImport("kernel32")] + private static extern long GetTickCount64(); +#endif + + /* DateTime.Now and DateTime.UtcNow depend on the system time which is undesirable. + * GetTickCount64 is unavailable on Windows XP and Windows Server 2003. + * Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, + * but expensive to call and unreliable with certain system configurations. + */ + + /* The following implementation is an effective substitute for GetTickCount64 that + * is reliable as long as it is retrieved once every 2^32 ms (~49 days). + */ + +#if Framework_4_0 + private static ThreadLocal _HighOrder = new ThreadLocal(); + private static ThreadLocal _LastTickCount = new ThreadLocal(); + + private static readonly long _Frequency = Stopwatch.Frequency; + + public static long TickCount { get { - if (Stopwatch.IsHighResolution) // TODO: GetTimestamp is unreliable with certain system configurations. - return (int)((double)Stopwatch.GetTimestamp() / Stopwatch.Frequency * 1000); - return Environment.TickCount; + if (Stopwatch.IsHighResolution) // TODO: Unreliable with certain system configurations. + return (long)((double)Stopwatch.GetTimestamp() / _Frequency * 1000); + + uint t = (uint)Environment.TickCount; + + if (_LastTickCount.Value > t) // Wrapped + _HighOrder.Value += 0x100000000; + + _LastTickCount.Value = t; + + return _HighOrder.Value | _LastTickCount.Value; } } +#else + private static long _HighOrder; + private static uint _LastTickCount; + + private static object _TickSync = new object(); + + private static readonly long _Frequency = Stopwatch.Frequency; + + public static long TickCount + { + get + { + if (Stopwatch.IsHighResolution) // TODO: Unreliable with certain system configurations. + return (long)((double)Stopwatch.GetTimestamp() / _Frequency * 1000); + + lock (_TickSync) + { + uint t = (uint)Environment.TickCount; + + if (_LastTickCount > t) // Wrapped + _HighOrder += 0x100000000; + + _LastTickCount = t; + + return _HighOrder | _LastTickCount; + } + } + } +#endif #if Framework_4_0 public static readonly bool Is64Bit = Environment.Is64BitProcess; @@ -513,10 +571,10 @@ namespace Server try { - DateTime now, last = DateTime.UtcNow; + long now, last = TickCount; const int sampleInterval = 100; - const float ticksPerSecond = (float)(TimeSpan.TicksPerSecond * sampleInterval); + const float ticksPerSecond = (float)(1000 * sampleInterval); TimeSpan _oneMS = TimeSpan.FromMilliseconds( 1 ); long sample = 0; @@ -539,9 +597,9 @@ namespace Server if( (++sample % sampleInterval) == 0 ) { - now = DateTime.UtcNow; + now = TickCount; m_CyclesPerSecond[m_CycleIndex++ % m_CyclesPerSecond.Length] = - ticksPerSecond / (now.Ticks - last.Ticks); + ticksPerSecond / (now - last); last = now; } } diff --git a/Server/Mobile.cs b/Server/Mobile.cs index a69b2b62a..a0d5275ce 100644 --- a/Server/Mobile.cs +++ b/Server/Mobile.cs @@ -660,11 +660,11 @@ namespace Server private class MovementRecord { - public int m_End; + public long m_End; private static Queue m_InstancePool = new Queue(); - public static MovementRecord NewInstance( int end ) + public static MovementRecord NewInstance( long end ) { MovementRecord r; @@ -682,7 +682,7 @@ namespace Server return r; } - private MovementRecord( int end ) + private MovementRecord( long end ) { m_End = end; } @@ -744,7 +744,7 @@ namespace Server private int m_TithingPoints; private bool m_DisplayGuildTitle; private Mobile m_GuildFealty; - private int m_NextSpellTime; + private long m_NextSpellTime; private DateTime[] m_StuckMenuUses; private Timer m_ExpireCombatant; private Timer m_ExpireCriminal; @@ -752,9 +752,9 @@ namespace Server private Timer m_LogoutTimer; private Timer m_CombatTimer; private Timer m_ManaTimer, m_HitsTimer, m_StamTimer; - private int m_NextSkillTime; - private int m_NextActionTime; - private int m_NextActionMessage; + private long m_NextSkillTime; + private long m_NextActionTime; + private long m_NextActionMessage; private bool m_Paralyzed; private ParalyzedTimer m_ParaTimer; private bool m_Frozen; @@ -1482,7 +1482,7 @@ namespace Server } } - public int NextCombatTime + public long NextCombatTime { get { @@ -1586,7 +1586,7 @@ namespace Server } } - private int m_LastMoveTime; + private long m_LastMoveTime; /// /// Gets or sets the number of steps this player may take when hidden before being revealed. @@ -1664,7 +1664,7 @@ namespace Server } } - public int LastMoveTime + public long LastMoveTime { get { @@ -1845,7 +1845,7 @@ namespace Server return String.Format( "0x{0:X} \"{1}\"", m_Serial.Value, Name ); } - public int NextActionTime + public long NextActionTime { get { @@ -1857,7 +1857,7 @@ namespace Server } } - public int NextActionMessage + public long NextActionMessage { get { @@ -2157,9 +2157,9 @@ namespace Server #endregion - private int m_NextCombatTime; + private long m_NextCombatTime; - public int NextSkillTime + public long NextSkillTime { get { @@ -3078,7 +3078,7 @@ namespace Server public static int WalkMount { get { return m_WalkMount; } set { m_WalkMount = value; } } public static int RunMount { get { return m_RunMount; } set { m_RunMount = value; } } - private int m_EndQueue; + private long m_EndQueue; private static ArrayList m_MoveList = new ArrayList(); @@ -3279,7 +3279,7 @@ namespace Server int delay = ComputeMovementSpeed( d ); - int end; + long end; if( m_MoveRecords.Count > 0 ) end = m_EndQueue + delay; @@ -11335,7 +11335,7 @@ namespace Server } } - public int NextSpellTime + public long NextSpellTime { get { diff --git a/Server/Network/NetState.cs b/Server/Network/NetState.cs index ad4c20b94..78e5a4615 100644 --- a/Server/Network/NetState.cs +++ b/Server/Network/NetState.cs @@ -1025,7 +1025,7 @@ namespace Server.Network { } } - private int m_NextCheckActivity; + private long m_NextCheckActivity; public bool CheckAlive() { if ( m_Socket == null )