commit
54a77a059b
7 changed files with 199 additions and 112 deletions
|
|
@ -1,10 +1,12 @@
|
|||
<?xml version="1.0"?>
|
||||
<configuration>
|
||||
<runtime>
|
||||
<gcServer enabled="true" />
|
||||
</runtime>
|
||||
<!--
|
||||
MONO/Linux users will need to uncomment and modify the following line:
|
||||
-->
|
||||
<!--<dllmap dll="libz" target="/lib/x86_64-linux-gnu/libz.so.1" />-->
|
||||
<?xml version="1.0"?>
|
||||
|
||||
<configuration>
|
||||
<startup>
|
||||
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.0" />
|
||||
</startup>
|
||||
<runtime>
|
||||
<gcServer enabled="true" />
|
||||
</runtime>
|
||||
<!--MONO/Linux users will need to uncomment and modify the following line:-->
|
||||
<!--<dllmap dll="libz" target="/lib/x86_64-linux-gnu/libz.so.1" />-->
|
||||
</configuration>
|
||||
|
|
@ -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( "<html>" );
|
||||
op.WriteLine( " <head>" );
|
||||
op.WriteLine( " <title>RunUO Server Status</title>");
|
||||
op.WriteLine( " </head>" );
|
||||
op.WriteLine( " <body bgcolor=\"white\">" );
|
||||
op.WriteLine( " <h1>RunUO Server Status</h1>" );
|
||||
op.WriteLine( " Online clients:<br>" );
|
||||
op.WriteLine( " <table width=\"100%\">" );
|
||||
op.WriteLine( " <tr>" );
|
||||
op.WriteLine( " <td bgcolor=\"black\"><font color=\"white\">Name</font></td><td bgcolor=\"black\"><font color=\"white\">Location</font></td><td bgcolor=\"black\"><font color=\"white\">Kills</font></td><td bgcolor=\"black\"><font color=\"white\">Karma / Fame</font></td>" );
|
||||
op.WriteLine( " </tr>" );
|
||||
Directory.CreateDirectory("web");
|
||||
}
|
||||
|
||||
foreach ( NetState state in NetState.Instances )
|
||||
using (var op = new StreamWriter("web/status.html"))
|
||||
{
|
||||
op.WriteLine("<!DOCTYPE html>");
|
||||
op.WriteLine("<html>");
|
||||
op.WriteLine(" <head>");
|
||||
op.WriteLine(" <title>" + ServerList.ServerName + " Server Status</title>");
|
||||
op.WriteLine(" </head>");
|
||||
op.WriteLine(" <style type=\"text/css\">");
|
||||
op.WriteLine(" body { background: #999; }");
|
||||
op.WriteLine(" table { width: 100%; }");
|
||||
op.WriteLine(" tr.ruo-header td { background: #000; color: #FFF; }");
|
||||
op.WriteLine(" tr.odd td { background: #222; color: #DDD; }");
|
||||
op.WriteLine(" tr.even td { background: #DDD; color: #222; }");
|
||||
op.WriteLine(" </style>");
|
||||
op.WriteLine(" <body>");
|
||||
op.WriteLine(" <h1>RunUO Server Status</h1>");
|
||||
op.WriteLine(" <h3>Online clients</h3>");
|
||||
op.WriteLine(" <table cellpadding=\"0\" cellspacing=\"0\">");
|
||||
op.WriteLine(" <tr class=\"ruo-header\"><td>Name</td><td>Location</td><td>Kills</td><td>Karma/Fame</td></tr>");
|
||||
|
||||
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(" <tr class=\"ruo-result " + (index % 2 == 0 ? "even" : "odd") + "\"><td>");
|
||||
|
||||
if (g != null)
|
||||
{
|
||||
Guild g = m.Guild as Guild;
|
||||
op.Write(Encode(m.Name));
|
||||
op.Write(" [");
|
||||
|
||||
op.Write( " <tr><td>" );
|
||||
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( "</td><td>" );
|
||||
op.Write( m.X );
|
||||
op.Write( ", " );
|
||||
op.Write( m.Y );
|
||||
op.Write( ", " );
|
||||
op.Write( m.Z );
|
||||
op.Write( " (" );
|
||||
op.Write( m.Map );
|
||||
op.Write( ")</td><td>" );
|
||||
op.Write( m.Kills );
|
||||
op.Write( "</td><td>" );
|
||||
op.Write( m.Karma );
|
||||
op.Write( " / " );
|
||||
op.Write( m.Fame );
|
||||
op.WriteLine( "</td></tr>" );
|
||||
op.Write(Encode(g.Abbreviation));
|
||||
|
||||
op.Write(']');
|
||||
}
|
||||
else
|
||||
{
|
||||
op.Write(Encode(m.Name));
|
||||
}
|
||||
|
||||
op.Write("</td><td>");
|
||||
op.Write(m.X);
|
||||
op.Write(", ");
|
||||
op.Write(m.Y);
|
||||
op.Write(", ");
|
||||
op.Write(m.Z);
|
||||
op.Write(" (");
|
||||
op.Write(m.Map);
|
||||
op.Write(")</td><td>");
|
||||
op.Write(m.Kills);
|
||||
op.Write("</td><td>");
|
||||
op.Write(m.Karma);
|
||||
op.Write(" / ");
|
||||
op.Write(m.Fame);
|
||||
op.WriteLine("</td></tr>");
|
||||
}
|
||||
|
||||
op.WriteLine( " <tr>" );
|
||||
op.WriteLine( " </table>" );
|
||||
op.WriteLine( " </body>" );
|
||||
op.WriteLine( "</html>" );
|
||||
op.WriteLine(" <tr>");
|
||||
op.WriteLine(" </table>");
|
||||
op.WriteLine(" </body>");
|
||||
op.WriteLine("</html>");
|
||||
}
|
||||
|
||||
lock (_StatusLock)
|
||||
{
|
||||
_StatusPage = File.ReadAllText("web/status.html");
|
||||
_StatusBuffer = Encoding.UTF8.GetBytes(_StatusPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@
|
|||
<ProjectGuid>{DAE872E6-6899-427C-A75D-AD52526EBCDA}</ProjectGuid>
|
||||
<OutputType>Library</OutputType>
|
||||
<NoStandardLibraries>false</NoStandardLibraries>
|
||||
<AssemblyName>RunUO Scripts</AssemblyName>
|
||||
<AssemblyName>Scripts.CS</AssemblyName>
|
||||
<TargetFrameworkVersion>v4.0</TargetFrameworkVersion>
|
||||
<FileAlignment>512</FileAlignment>
|
||||
<TargetFrameworkProfile>
|
||||
|
|
@ -17,17 +17,19 @@
|
|||
<DebugType>full</DebugType>
|
||||
<Optimize>false</Optimize>
|
||||
<OutputPath>Output\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<Optimize>true</Optimize>
|
||||
<OutputPath>Output\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<WarningLevel>4</WarningLevel>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<RootNamespace>Server</RootNamespace>
|
||||
|
|
@ -35,21 +37,22 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>Output\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>true</UseVSHostingProcess>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>bin\x64\Release\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<OutputPath>Output\</OutputPath>
|
||||
<DefineConstants>TRACE;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
|
|
|||
|
|
@ -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<long> _HighOrder = new ThreadLocal<long>();
|
||||
private static ThreadLocal<uint> _LastTickCount = new ThreadLocal<uint>();
|
||||
*/
|
||||
|
||||
private static readonly bool _HighRes = Stopwatch.IsHighResolution;
|
||||
|
||||
private static readonly double _HighFrequency = 1000.0 / Stopwatch.Frequency;
|
||||
|
|
|
|||
|
|
@ -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<T> _Pool;
|
||||
private List<T> _Pool;
|
||||
|
||||
public PooledEnumerable(IEnumerable<T> pool)
|
||||
{
|
||||
_Pool = pool;
|
||||
_Pool = new List<T>(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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -39,42 +39,46 @@
|
|||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|AnyCPU'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|AnyCPU'">
|
||||
<OutputPath>..\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
|
||||
<DebugSymbols>true</DebugSymbols>
|
||||
<OutputPath>..\</OutputPath>
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;DEBUG;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
|
||||
<OutputPath>..\</OutputPath>
|
||||
<DefineConstants>TRACE</DefineConstants>
|
||||
<DefineConstants>TRACE;NEWTIMERS, NEWPARENT</DefineConstants>
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<UseVSHostingProcess>false</UseVSHostingProcess>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Microsoft.CSharp" />
|
||||
|
|
|
|||
|
|
@ -313,6 +313,12 @@ namespace Server
|
|||
|
||||
while ( !Core.Closing )
|
||||
{
|
||||
if (World.Loading || World.Saving)
|
||||
{
|
||||
m_Signal.WaitOne(1, false);
|
||||
continue;
|
||||
}
|
||||
|
||||
ProcessChanged();
|
||||
|
||||
loaded = false;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue