diff --git a/RunUO.exe.config b/RunUO.exe.config index 5106eb6a4..3fe506032 100644 --- a/RunUO.exe.config +++ b/RunUO.exe.config @@ -1,10 +1,12 @@ - - - - - - - + + + + + + + + + + + \ No newline at end of file diff --git a/Scripts/Misc/WebStatus.cs b/Scripts/Misc/WebStatus.cs index 4401d6728..ae8895929 100644 --- a/Scripts/Misc/WebStatus.cs +++ b/Scripts/Misc/WebStatus.cs @@ -1,118 +1,193 @@ +#region References using System; using System.IO; +using System.Linq; +using System.Net; using System.Text; -using Server; -using Server.Network; + using Server.Guilds; +using Server.Network; +#endregion namespace Server.Misc { public class StatusPage : Timer { - public static bool Enabled = false; + public static readonly bool Enabled = false; + + private static HttpListener _Listener; + + private static string _StatusPage = String.Empty; + private static byte[] _StatusBuffer = new byte[0]; + + private static readonly object _StatusLock = new object(); public static void Initialize() { - if ( Enabled ) - new StatusPage().Start(); + if (!Enabled) + { + return; + } + + new StatusPage().Start(); + + Listen(); } - public StatusPage() : base( TimeSpan.FromSeconds( 5.0 ), TimeSpan.FromSeconds( 60.0 ) ) + private static void Listen() { - Priority = TimerPriority.FiveSeconds; + if (!HttpListener.IsSupported) + { + return; + } + + if (_Listener == null) + { + _Listener = new HttpListener(); + _Listener.Prefixes.Add("http://*:80/status/"); + _Listener.Start(); + } + else if (!_Listener.IsListening) + { + _Listener.Start(); + } + + if (_Listener.IsListening) + { + _Listener.BeginGetContext(ListenerCallback, null); + } } - private static string Encode( string input ) + private static void ListenerCallback(IAsyncResult result) { - StringBuilder sb = new StringBuilder( input ); + try + { + var context = _Listener.EndGetContext(result); - sb.Replace( "&", "&" ); - sb.Replace( "<", "<" ); - sb.Replace( ">", ">" ); - sb.Replace( "\"", """ ); - sb.Replace( "'", "'" ); + byte[] buffer; + + lock (_StatusLock) + { + buffer = _StatusBuffer; + } + + context.Response.ContentLength64 = buffer.Length; + context.Response.OutputStream.Write(buffer, 0, buffer.Length); + context.Response.OutputStream.Close(); + } + catch + { } + + Listen(); + } + + private static string Encode(string input) + { + var sb = new StringBuilder(input); + + sb.Replace("&", "&"); + sb.Replace("<", "<"); + sb.Replace(">", ">"); + sb.Replace("\"", """); + sb.Replace("'", "'"); return sb.ToString(); } + public StatusPage() + : base(TimeSpan.FromSeconds(5.0), TimeSpan.FromSeconds(60.0)) + { + Priority = TimerPriority.FiveSeconds; + } + protected override void OnTick() { - if ( !Directory.Exists( "web" ) ) - Directory.CreateDirectory( "web" ); - - using ( StreamWriter op = new StreamWriter( "web/status.html" ) ) + if (!Directory.Exists("web")) { - op.WriteLine( "" ); - op.WriteLine( " " ); - op.WriteLine( " RunUO Server Status"); - op.WriteLine( " " ); - op.WriteLine( " " ); - op.WriteLine( "

RunUO Server Status

" ); - op.WriteLine( " Online clients:
" ); - op.WriteLine( " " ); - op.WriteLine( " " ); - op.WriteLine( " " ); - op.WriteLine( " " ); + Directory.CreateDirectory("web"); + } - foreach ( NetState state in NetState.Instances ) + using (var op = new StreamWriter("web/status.html")) + { + op.WriteLine(""); + op.WriteLine(""); + op.WriteLine(" "); + op.WriteLine(" " + ServerList.ServerName + " Server Status"); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine("

RunUO Server Status

"); + op.WriteLine("

Online clients

"); + op.WriteLine("
NameLocationKillsKarma / Fame
"); + op.WriteLine(" "); + + var index = 0; + + foreach (var m in NetState.Instances.Where(state => state.Mobile != null).Select(state => state.Mobile)) { - Mobile m = state.Mobile; + ++index; - if ( m != null ) + var g = m.Guild as Guild; + + op.Write(" " ); + op.Write(Encode(g.Abbreviation)); + + op.Write(']'); } + else + { + op.Write(Encode(m.Name)); + } + + op.Write(""); } - op.WriteLine( " " ); - op.WriteLine( "
NameLocationKillsKarma/Fame
"); + + if (g != null) { - Guild g = m.Guild as Guild; + op.Write(Encode(m.Name)); + op.Write(" ["); - op.Write( "
" ); + var title = m.GuildTitle; - if ( g != null ) + title = title != null ? title.Trim() : String.Empty; + + if (title.Length > 0) { - op.Write( Encode( m.Name ) ); - op.Write( " [" ); - - string title = m.GuildTitle; - - if ( title != null ) - title = title.Trim(); - else - title = ""; - - if ( title.Length > 0 ) - { - op.Write( Encode( title ) ); - op.Write( ", " ); - } - - op.Write( Encode( g.Abbreviation ) ); - - op.Write( ']' ); - } - else - { - op.Write( Encode( m.Name ) ); + op.Write(Encode(title)); + op.Write(", "); } - op.Write( "" ); - op.Write( m.X ); - op.Write( ", " ); - op.Write( m.Y ); - op.Write( ", " ); - op.Write( m.Z ); - op.Write( " (" ); - op.Write( m.Map ); - op.Write( ")" ); - op.Write( m.Kills ); - op.Write( "" ); - op.Write( m.Karma ); - op.Write( " / " ); - op.Write( m.Fame ); - op.WriteLine( "
"); + op.Write(m.X); + op.Write(", "); + op.Write(m.Y); + op.Write(", "); + op.Write(m.Z); + op.Write(" ("); + op.Write(m.Map); + op.Write(")"); + op.Write(m.Kills); + op.Write(""); + op.Write(m.Karma); + op.Write(" / "); + op.Write(m.Fame); + op.WriteLine("
" ); - op.WriteLine( " " ); - op.WriteLine( "" ); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine(" "); + op.WriteLine(""); + } + + lock (_StatusLock) + { + _StatusPage = File.ReadAllText("web/status.html"); + _StatusBuffer = Encoding.UTF8.GetBytes(_StatusPage); } } } diff --git a/Scripts/Scripts.csproj b/Scripts/Scripts.csproj index 558fdb002..a13e646dd 100644 --- a/Scripts/Scripts.csproj +++ b/Scripts/Scripts.csproj @@ -6,7 +6,7 @@ {DAE872E6-6899-427C-A75D-AD52526EBCDA} Library false - RunUO Scripts + Scripts.CS v4.0 512 @@ -17,17 +17,19 @@ full false Output\ - DEBUG;TRACE + TRACE;DEBUG;NEWTIMERS, NEWPARENT prompt 4 + false pdbonly true Output\ - TRACE + TRACE;NEWTIMERS, NEWPARENT prompt 4 + false Server @@ -35,21 +37,22 @@ true Output\ - DEBUG;TRACE + TRACE;DEBUG;NEWTIMERS, NEWPARENT full x64 prompt MinimumRecommendedRules.ruleset - true + false - bin\x64\Release\ - TRACE + Output\ + TRACE;NEWTIMERS, NEWPARENT true pdbonly x64 prompt MinimumRecommendedRules.ruleset + false diff --git a/Server/Main.cs b/Server/Main.cs index 1bf17cc35..14f029207 100644 --- a/Server/Main.cs +++ b/Server/Main.cs @@ -107,23 +107,17 @@ namespace Server public static Thread Thread { get { return m_Thread; } } public static MultiTextWriter MultiConsoleOut { get { return m_MultiConOut; } } - /* DateTime.Now and DateTime.UtcNow are based on actual system clock time. + /* + * DateTime.Now and DateTime.UtcNow are based on actual system clock time. * The resolution is acceptable but large clock jumps are possible and cause issues. * GetTickCount and GetTickCount64 have poor resolution. * GetTickCount64 is unavailable on Windows XP and Windows Server 2003. * Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, but - * somewhat expensive to call and unreliable with certain system configurations. + * somewhat expensive to call because of its defference to DateTime.Now, + * which is why Stopwatch has been used to verify HRT before calling GetTimestamp(), + * enabling the usage of DateTime.UtcNow instead. */ - /* The following implementation contains an effective substitute for GetTickCount64 that - * is reliable as long as it is retrieved once every 2^32 ms (~49 days). - */ - - /* We don't really need this, but it may be useful in the future. - private static ThreadLocal _HighOrder = new ThreadLocal(); - private static ThreadLocal _LastTickCount = new ThreadLocal(); - */ - private static readonly bool _HighRes = Stopwatch.IsHighResolution; private static readonly double _HighFrequency = 1000.0 / Stopwatch.Frequency; diff --git a/Server/Map.cs b/Server/Map.cs index f4580c557..1a0c30b1a 100644 --- a/Server/Map.cs +++ b/Server/Map.cs @@ -1743,7 +1743,7 @@ namespace Server if (e != null) { - e._Pool = pool; + e._Pool.AddRange(pool); } else { @@ -1754,11 +1754,11 @@ namespace Server } private bool _IsDisposed; - private IEnumerable _Pool; + private List _Pool; public PooledEnumerable(IEnumerable pool) { - _Pool = pool; + _Pool = new List(pool); } IEnumerator IEnumerable.GetEnumerator() @@ -1778,7 +1778,7 @@ namespace Server return; } - _Pool = null; + _Pool.Clear(); lock (((ICollection)_Buffer).SyncRoot) { @@ -1789,6 +1789,9 @@ namespace Server public void Dispose() { _IsDisposed = true; + + _Pool.Clear(); + _Pool.TrimExcess(); _Pool = null; } } diff --git a/Server/Server.csproj b/Server/Server.csproj index 6ddcb8dc3..62bfacff4 100644 --- a/Server/Server.csproj +++ b/Server/Server.csproj @@ -39,42 +39,46 @@ true ..\ - DEBUG;TRACE + TRACE;DEBUG;NEWTIMERS, NEWPARENT true full AnyCPU prompt MinimumRecommendedRules.ruleset + false ..\ - TRACE + TRACE;NEWTIMERS, NEWPARENT true true pdbonly AnyCPU prompt MinimumRecommendedRules.ruleset + false true ..\ - DEBUG;TRACE + TRACE;DEBUG;NEWTIMERS, NEWPARENT true full x64 prompt MinimumRecommendedRules.ruleset + false ..\ - TRACE + TRACE;NEWTIMERS, NEWPARENT true true pdbonly x64 prompt MinimumRecommendedRules.ruleset + false diff --git a/Server/Timer.cs b/Server/Timer.cs index 6c1170eb6..f3aa7a21e 100644 --- a/Server/Timer.cs +++ b/Server/Timer.cs @@ -313,6 +313,12 @@ namespace Server while ( !Core.Closing ) { + if (World.Loading || World.Saving) + { + m_Signal.WaitOne(1, false); + continue; + } + ProcessChanged(); loaded = false;