Targets .NET Core 3.0 (#39)
This commit is contained in:
parent
0993c03b70
commit
08bf44af9a
125 changed files with 1473 additions and 14244 deletions
|
|
@ -1,5 +1,3 @@
|
|||
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeSmithBOD : LargeBOD
|
||||
|
|
|
|||
|
|
@ -1,5 +1,3 @@
|
|||
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
public class LargeTailorBOD : LargeBOD
|
||||
|
|
|
|||
|
|
@ -1,7 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Engines.Craft;
|
||||
using Mat = Server.Engines.BulkOrders.BulkMaterialType;
|
||||
|
||||
namespace Server.Engines.BulkOrders
|
||||
{
|
||||
|
|
|
|||
|
|
@ -271,11 +271,7 @@ namespace Server.Factions
|
|||
|
||||
public void Invalidate()
|
||||
{
|
||||
if (Mobile is PlayerMobile pm)
|
||||
{
|
||||
pm.InvalidateProperties();
|
||||
pm.InvalidateMyRunUO();
|
||||
}
|
||||
(Mobile as PlayerMobile)?.InvalidateProperties();
|
||||
}
|
||||
|
||||
public void Attach()
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ namespace Server.Engines.Help
|
|||
if (entry != null && entry.Handler == null)
|
||||
{
|
||||
m_From.SendLocalizedMessage(1005307, "", 0x35); // Removed help request.
|
||||
entry.AddResponse(entry.Sender, "[Canceled]");
|
||||
// entry.AddResponse(entry.Sender, "[Canceled]");
|
||||
PageQueue.Remove(entry);
|
||||
}
|
||||
else
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.IO;
|
|||
using System.Net.Mail;
|
||||
using Server.Accounting;
|
||||
using Server.Commands;
|
||||
using Server.Engines.Reports;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
|
@ -49,19 +48,8 @@ namespace Server.Engines.Help
|
|||
|
||||
m_Timer = new InternalTimer(this);
|
||||
m_Timer.Start();
|
||||
|
||||
StaffHistory history = Reports.Reports.StaffHistory;
|
||||
|
||||
if (history != null)
|
||||
{
|
||||
PageInfo = new PageInfo(this);
|
||||
|
||||
history.AddPage(PageInfo);
|
||||
}
|
||||
}
|
||||
|
||||
public PageInfo PageInfo{ get; }
|
||||
|
||||
public Mobile Sender{ get; }
|
||||
|
||||
public Mobile Handler
|
||||
|
|
@ -93,20 +81,6 @@ namespace Server.Engines.Help
|
|||
m_Timer = null;
|
||||
}
|
||||
|
||||
public void AddResponse(Mobile mob, string text)
|
||||
{
|
||||
if (PageInfo != null)
|
||||
{
|
||||
lock (PageInfo)
|
||||
{
|
||||
PageInfo.Responses.Add(PageInfo.GetAccount(mob), text);
|
||||
}
|
||||
|
||||
if (PageInfo.ResFromResp(text) != PageResolution.None)
|
||||
PageInfo.UpdateResolver();
|
||||
}
|
||||
}
|
||||
|
||||
private class InternalTimer : Timer
|
||||
{
|
||||
private static TimeSpan StatusDelay = TimeSpan.FromMinutes(2.0);
|
||||
|
|
@ -135,7 +109,7 @@ namespace Server.Engines.Help
|
|||
else
|
||||
{
|
||||
if (index != -1)
|
||||
m_Entry.AddResponse(m_Entry.Sender, "[Logout]");
|
||||
// m_Entry.AddResponse(m_Entry.Sender, "[Logout]");
|
||||
|
||||
PageQueue.Remove(m_Entry);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ namespace Server.Engines.Help
|
|||
|
||||
if (e.Sender.Deleted || e.Sender.NetState == null)
|
||||
{
|
||||
e.AddResponse(e.Sender, "[Logout]");
|
||||
// e.AddResponse(e.Sender, "[Logout]");
|
||||
PageQueue.Remove(e);
|
||||
}
|
||||
else
|
||||
|
|
@ -601,7 +601,7 @@ namespace Server.Engines.Help
|
|||
}
|
||||
else
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Go Sender]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Go Sender]");
|
||||
m.MoveToWorld(m_Entry.Sender.Location, m_Entry.Sender.Map);
|
||||
|
||||
m.SendMessage("You have been teleported to that page's sender.");
|
||||
|
|
@ -628,7 +628,7 @@ namespace Server.Engines.Help
|
|||
}
|
||||
else
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Go Handler]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Go Handler]");
|
||||
m.MoveToWorld(h.Location, h.Map);
|
||||
|
||||
m.SendMessage("You have been teleported to that page's handler.");
|
||||
|
|
@ -653,7 +653,7 @@ namespace Server.Engines.Help
|
|||
}
|
||||
else
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Go PageLoc]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Go PageLoc]");
|
||||
m.MoveToWorld(m_Entry.PageLocation, m_Entry.PageMap);
|
||||
|
||||
state.Mobile.SendMessage("You have been teleported to the original page location.");
|
||||
|
|
@ -667,7 +667,7 @@ namespace Server.Engines.Help
|
|||
{
|
||||
if (m_Entry.Handler == null)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Handling]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Handling]");
|
||||
m_Entry.Handler = state.Mobile;
|
||||
|
||||
state.Mobile.SendMessage("You are now handling the page.");
|
||||
|
|
@ -685,7 +685,7 @@ namespace Server.Engines.Help
|
|||
{
|
||||
if (m_Entry.Handler == null)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Deleting]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Deleting]");
|
||||
PageQueue.Remove(m_Entry);
|
||||
|
||||
state.Mobile.SendMessage("You delete the page.");
|
||||
|
|
@ -707,7 +707,7 @@ namespace Server.Engines.Help
|
|||
{
|
||||
if (m_Entry.Handler == state.Mobile)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Abandoning]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Abandoning]");
|
||||
state.Mobile.SendMessage("You abandon the page.");
|
||||
|
||||
m_Entry.Handler = null;
|
||||
|
|
@ -725,7 +725,7 @@ namespace Server.Engines.Help
|
|||
{
|
||||
if (m_Entry.Handler == state.Mobile)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Handled]");
|
||||
// m_Entry.AddResponse(state.Mobile, "[Handled]");
|
||||
PageQueue.Remove(m_Entry);
|
||||
|
||||
m_Entry.Handler = null;
|
||||
|
|
@ -751,7 +751,7 @@ namespace Server.Engines.Help
|
|||
|
||||
if (text != null)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[Response] " + text.Text);
|
||||
// m_Entry.AddResponse(state.Mobile, "[Response] " + text.Text);
|
||||
m_Entry.Sender.SendGump(new MessageSentGump(m_Entry.Sender, state.Mobile.Name, text.Text));
|
||||
//m_Entry.Sender.SendMessage( 0x482, "{0} tells you:", state.Mobile.Name );
|
||||
//m_Entry.Sender.SendMessage( 0x482, text.Text );
|
||||
|
|
@ -786,7 +786,7 @@ namespace Server.Engines.Help
|
|||
|
||||
if (index >= 0 && index < preresp.Count)
|
||||
{
|
||||
m_Entry.AddResponse(state.Mobile, "[PreDef] " + preresp[index].Title);
|
||||
// m_Entry.AddResponse(state.Mobile, "[PreDef] " + preresp[index].Title);
|
||||
m_Entry.Sender.SendGump(new MessageSentGump(m_Entry.Sender, state.Mobile.Name,
|
||||
preresp[index].Message));
|
||||
}
|
||||
|
|
|
|||
|
|
@ -177,7 +177,7 @@ namespace Server.Engines.MLQuests.Gumps
|
|||
IRaceChanger owner = raceChangeState.m_Owner;
|
||||
Race targetRace = raceChangeState.m_TargetRace;
|
||||
|
||||
if (pvSrc.Size == 5)
|
||||
if (pvSrc.Length == 5)
|
||||
{
|
||||
owner?.OnCancel(pm);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,251 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Data.Odbc;
|
||||
using System.Threading;
|
||||
|
||||
namespace Server.Engines.MyRunUO
|
||||
{
|
||||
public class DatabaseCommandQueue
|
||||
{
|
||||
private string m_CompletionString;
|
||||
private string m_ConnectionString;
|
||||
private Queue m_Queue;
|
||||
private ManualResetEvent m_Sync;
|
||||
|
||||
public DatabaseCommandQueue(string completionString, string threadName) : this(Config.CompileConnectionString(),
|
||||
completionString, threadName)
|
||||
{
|
||||
}
|
||||
|
||||
public DatabaseCommandQueue(string connectionString, string completionString, string threadName)
|
||||
{
|
||||
m_CompletionString = completionString;
|
||||
m_ConnectionString = connectionString;
|
||||
|
||||
m_Queue = Queue.Synchronized(new Queue());
|
||||
|
||||
m_Queue.Enqueue(null); // signal connect
|
||||
|
||||
/*m_Queue.Enqueue( "DELETE FROM myrunuo_characters" );
|
||||
m_Queue.Enqueue( "DELETE FROM myrunuo_characters_layers" );
|
||||
m_Queue.Enqueue( "DELETE FROM myrunuo_characters_skills" );
|
||||
m_Queue.Enqueue( "DELETE FROM myrunuo_guilds" );
|
||||
m_Queue.Enqueue( "DELETE FROM myrunuo_guilds_wars" );*/
|
||||
|
||||
m_Sync = new ManualResetEvent(true);
|
||||
|
||||
// MyRunUO Database Command Queue;
|
||||
Thread thread = new Thread(Thread_Start) { Name = threadName, Priority = Config.DatabaseThreadPriority };
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
public bool HasCompleted{ get; private set; }
|
||||
|
||||
public void Enqueue(object obj)
|
||||
{
|
||||
lock (m_Queue.SyncRoot)
|
||||
{
|
||||
m_Queue.Enqueue(obj);
|
||||
try
|
||||
{
|
||||
m_Sync.Set();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void Thread_Start()
|
||||
{
|
||||
bool connected = false;
|
||||
|
||||
OdbcConnection connection = null;
|
||||
OdbcCommand command = null;
|
||||
OdbcTransaction transact = null;
|
||||
|
||||
DateTime start = DateTime.UtcNow;
|
||||
|
||||
bool shouldWriteException = true;
|
||||
|
||||
while (true)
|
||||
{
|
||||
m_Sync.WaitOne();
|
||||
|
||||
while (m_Queue.Count > 0)
|
||||
try
|
||||
{
|
||||
object obj = m_Queue.Dequeue();
|
||||
|
||||
if (obj == null)
|
||||
{
|
||||
if (connected)
|
||||
{
|
||||
if (transact != null)
|
||||
try
|
||||
{
|
||||
transact.Commit();
|
||||
}
|
||||
catch (Exception commitException)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: Exception caught when committing transaction");
|
||||
Console.WriteLine(commitException);
|
||||
|
||||
try
|
||||
{
|
||||
transact.Rollback();
|
||||
Console.WriteLine("MyRunUO: Transaction has been rolled back");
|
||||
}
|
||||
catch (Exception rollbackException)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: Exception caught when rolling back transaction");
|
||||
Console.WriteLine(rollbackException);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connection.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connection.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
command.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_Sync.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Console.WriteLine(m_CompletionString, (DateTime.UtcNow - start).TotalSeconds);
|
||||
HasCompleted = true;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connected = true;
|
||||
connection = new OdbcConnection(m_ConnectionString);
|
||||
connection.Open();
|
||||
command = connection.CreateCommand();
|
||||
|
||||
if (Config.UseTransactions)
|
||||
{
|
||||
transact = connection.BeginTransaction();
|
||||
command.Transaction = transact;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
try
|
||||
{
|
||||
transact?.Rollback();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connection?.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
connection?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
command?.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
m_Sync.Close();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Console.WriteLine("MyRunUO: Unable to connect to the database");
|
||||
Console.WriteLine(e);
|
||||
HasCompleted = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
else if (obj is string s)
|
||||
{
|
||||
command.CommandText = s;
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
else
|
||||
{
|
||||
string[] parms = (string[])obj;
|
||||
|
||||
command.CommandText = parms[0];
|
||||
|
||||
if (command.ExecuteScalar() == null)
|
||||
{
|
||||
command.CommandText = parms[1];
|
||||
command.ExecuteNonQuery();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (shouldWriteException)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: Exception caught in database thread");
|
||||
Console.WriteLine(e);
|
||||
shouldWriteException = false;
|
||||
}
|
||||
}
|
||||
|
||||
lock (m_Queue.SyncRoot)
|
||||
{
|
||||
if (m_Queue.Count == 0)
|
||||
m_Sync.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,716 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Server.Accounting;
|
||||
using Server.Commands;
|
||||
using Server.Guilds;
|
||||
using Server.Misc;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Engines.MyRunUO
|
||||
{
|
||||
public class MyRunUO : Timer
|
||||
{
|
||||
public const char LineStart = '\"';
|
||||
public const string EntrySep = "\",\"";
|
||||
public const string LineEnd = "\"\n";
|
||||
private static double CpuInterval = 0.1; // Processor runs every 0.1 seconds
|
||||
|
||||
private static double
|
||||
CpuPercent = 0.25; // Processor runs for 25% of Interval, or ~25ms. This should take around 25% cpu
|
||||
|
||||
private static Timer m_Timer;
|
||||
|
||||
private static DatabaseCommandQueue m_Command;
|
||||
|
||||
private static List<Mobile> m_MobilesToUpdate = new List<Mobile>();
|
||||
private List<IAccount> m_Collecting;
|
||||
private int m_Index;
|
||||
|
||||
private List<Item> m_Items = new List<Item>();
|
||||
private string m_LayersPath;
|
||||
private ArrayList m_List;
|
||||
private string m_MobilesPath;
|
||||
private StreamWriter m_OpLayers;
|
||||
private StreamWriter m_OpMobiles;
|
||||
|
||||
private StreamWriter m_OpSkills;
|
||||
|
||||
private string m_SkillsPath;
|
||||
|
||||
private Stage m_Stage;
|
||||
|
||||
private DateTime m_StartTime;
|
||||
|
||||
public MyRunUO() : base(TimeSpan.FromSeconds(CpuInterval), TimeSpan.FromSeconds(CpuInterval))
|
||||
{
|
||||
m_List = new ArrayList();
|
||||
m_Collecting = new List<IAccount>();
|
||||
|
||||
m_StartTime = DateTime.UtcNow;
|
||||
Console.WriteLine("MyRunUO: Updating character database");
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (Config.Enabled)
|
||||
{
|
||||
DelayCall(TimeSpan.FromSeconds(10.0), Config.CharacterUpdateInterval, Begin);
|
||||
|
||||
CommandSystem.Register("InitMyRunUO", AccessLevel.Administrator, InitMyRunUO_OnCommand);
|
||||
CommandSystem.Register("UpdateMyRunUO", AccessLevel.Administrator, UpdateMyRunUO_OnCommand);
|
||||
|
||||
CommandSystem.Register("PublicChar", AccessLevel.Player, PublicChar_OnCommand);
|
||||
CommandSystem.Register("PrivateChar", AccessLevel.Player, PrivateChar_OnCommand);
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("PublicChar")]
|
||||
[Description("Enables showing extended character stats and skills in MyRunUO.")]
|
||||
public static void PublicChar_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (e.Mobile is PlayerMobile pm)
|
||||
{
|
||||
if (pm.PublicMyRunUO)
|
||||
{
|
||||
pm.SendMessage("You have already chosen to show your skills and stats.");
|
||||
}
|
||||
else
|
||||
{
|
||||
pm.PublicMyRunUO = true;
|
||||
pm.SendMessage("All of your skills and stats will now be shown publicly in MyRunUO.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("PrivateChar")]
|
||||
[Description("Disables showing extended character stats and skills in MyRunUO.")]
|
||||
public static void PrivateChar_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (e.Mobile is PlayerMobile pm)
|
||||
{
|
||||
if (!pm.PublicMyRunUO)
|
||||
{
|
||||
pm.SendMessage("You have already chosen to not show your skills and stats.");
|
||||
}
|
||||
else
|
||||
{
|
||||
pm.PublicMyRunUO = false;
|
||||
pm.SendMessage("Only a general level of your top three skills will be shown in MyRunUO.");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("InitMyRunUO")]
|
||||
[Description("Initially creates the database schema.")]
|
||||
public static void InitMyRunUO_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (m_Command?.HasCompleted == true)
|
||||
{
|
||||
TableCreation();
|
||||
e.Mobile.SendMessage("MyRunUO table creation process has been started.");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("MyRunUO table creation is already running.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void TableCreation()
|
||||
{
|
||||
if (m_Command?.HasCompleted == false)
|
||||
return;
|
||||
// DateTime start = DateTime.Now;
|
||||
Console.WriteLine("MyRunUO: Creating tables");
|
||||
try
|
||||
{
|
||||
m_Command = new DatabaseCommandQueue("MyRunUO: Tables created in {0:F1} seconds",
|
||||
"MyRunUO Status Database Thread");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_characters` ( `char_id` int(10) unsigned NOT NULL, `char_name` varchar(255) NOT NULL, `char_str` smallint(3) unsigned NOT NULL, `char_dex` smallint(3) unsigned NOT NULL, `char_int` smallint(3) unsigned NOT NULL, `char_female` tinyint(1) NOT NULL, `char_counts` smallint(6) NOT NULL, `char_guild` varchar(255) DEFAULT NULL, `char_guildtitle` varchar(255) DEFAULT NULL, `char_nototitle` varchar(255) DEFAULT NULL, `char_bodyhue` smallint(5) unsigned DEFAULT NULL, `char_public` tinyint(1) NOT NULL, PRIMARY KEY (`char_id`))");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_characters_layers` ( `char_id` int(10) unsigned NOT NULL, `layer_id` tinyint(3) unsigned NOT NULL, `item_id` smallint(5) unsigned NOT NULL, `item_hue` smallint(5) unsigned NOT NULL, PRIMARY KEY (`char_id`,`layer_id`))");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_characters_skills` ( `char_id` int(10) unsigned NOT NULL, `skill_id` tinyint(3) NOT NULL, `skill_value` smallint(5) unsigned NOT NULL, PRIMARY KEY (`char_id`,`skill_id`), KEY `skill_id` (`skill_id`))");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_guilds` ( `guild_id` smallint(5) unsigned NOT NULL, `guild_name` varchar(255) NOT NULL, `guild_abbreviation` varchar(8) DEFAULT NULL, `guild_website` varchar(255) DEFAULT NULL, `guild_charter` varchar(255) DEFAULT NULL, `guild_type` varchar(8) NOT NULL, `guild_wars` smallint(5) unsigned NOT NULL, `guild_members` smallint(5) unsigned NOT NULL, `guild_master` int(10) unsigned NOT NULL, PRIMARY KEY (`guild_id`))");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_guilds_wars` ( `guild_1` smallint(5) unsigned NOT NULL DEFAULT '0', `guild_2` smallint(5) unsigned NOT NULL DEFAULT '0', PRIMARY KEY (`guild_1`,`guild_2`), KEY `guild1` (`guild_1`), KEY `guild2` (`guild_2`))");
|
||||
m_Command.Enqueue(
|
||||
"CREATE TABLE IF NOT EXISTS `myrunuo_status` ( `char_id` int(10) NOT NULL, PRIMARY KEY (`char_id`))");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: Error creating tables.");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
m_Command?.Enqueue(null);
|
||||
}
|
||||
|
||||
[Usage("UpdateMyRunUO")]
|
||||
[Description("Starts the process of updating the MyRunUO character and guild database.")]
|
||||
public static void UpdateMyRunUO_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (m_Command?.HasCompleted == true)
|
||||
m_Command = null;
|
||||
|
||||
if (m_Timer == null && m_Command == null)
|
||||
{
|
||||
Begin();
|
||||
e.Mobile.SendMessage("MyRunUO update process has been started.");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("MyRunUO database is already being updated.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Begin()
|
||||
{
|
||||
if (m_Command?.HasCompleted == true)
|
||||
m_Command = null;
|
||||
|
||||
if (m_Timer != null || m_Command != null)
|
||||
return;
|
||||
|
||||
m_Timer = new MyRunUO();
|
||||
m_Timer.Start();
|
||||
}
|
||||
|
||||
protected override void OnTick()
|
||||
{
|
||||
bool shouldExit;
|
||||
|
||||
try
|
||||
{
|
||||
shouldExit = Process(DateTime.UtcNow + TimeSpan.FromSeconds(CpuInterval * CpuPercent));
|
||||
|
||||
if (shouldExit)
|
||||
Console.WriteLine("MyRunUO: Database statements compiled in {0:F2} seconds",
|
||||
(DateTime.UtcNow - m_StartTime).TotalSeconds);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: {0}: Exception cought while processing", m_Stage);
|
||||
Console.WriteLine(e);
|
||||
shouldExit = true;
|
||||
}
|
||||
|
||||
if (shouldExit)
|
||||
{
|
||||
m_Command.Enqueue(null);
|
||||
|
||||
Stop();
|
||||
m_Timer = null;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Process(DateTime endTime)
|
||||
{
|
||||
switch (m_Stage)
|
||||
{
|
||||
case Stage.CollectingMobiles:
|
||||
CollectMobiles(endTime);
|
||||
break;
|
||||
case Stage.DumpingMobiles:
|
||||
DumpMobiles(endTime);
|
||||
break;
|
||||
case Stage.CollectingGuilds:
|
||||
CollectGuilds(endTime);
|
||||
break;
|
||||
case Stage.DumpingGuilds:
|
||||
DumpGuilds(endTime);
|
||||
break;
|
||||
}
|
||||
|
||||
return m_Stage == Stage.Complete;
|
||||
}
|
||||
|
||||
public static void QueueMobileUpdate(Mobile m)
|
||||
{
|
||||
if (!Config.Enabled || Config.LoadDataInFile)
|
||||
return;
|
||||
|
||||
m_MobilesToUpdate.Add(m);
|
||||
}
|
||||
|
||||
public void CollectMobiles(DateTime endTime)
|
||||
{
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
if (m_Index == 0)
|
||||
m_Collecting.AddRange(Accounts.GetAccounts());
|
||||
|
||||
for (int i = m_Index; i < m_Collecting.Count; ++i)
|
||||
{
|
||||
IAccount acct = m_Collecting[i];
|
||||
|
||||
for (int j = 0; j < acct.Length; ++j)
|
||||
{
|
||||
Mobile mob = acct[j];
|
||||
|
||||
if (mob?.AccessLevel < Config.HiddenAccessLevel)
|
||||
m_List.Add(mob);
|
||||
}
|
||||
|
||||
++m_Index;
|
||||
|
||||
if (DateTime.UtcNow >= endTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_Index == m_Collecting.Count)
|
||||
{
|
||||
m_Collecting = new List<IAccount>();
|
||||
m_Stage = Stage.DumpingMobiles;
|
||||
m_Index = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_List = new ArrayList(m_MobilesToUpdate);
|
||||
m_MobilesToUpdate = new List<Mobile>();
|
||||
m_Stage = Stage.DumpingMobiles;
|
||||
m_Index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public void CheckConnection()
|
||||
{
|
||||
if (m_Command == null)
|
||||
{
|
||||
m_Command = new DatabaseCommandQueue("MyRunUO: Character database updated in {0:F1} seconds",
|
||||
"MyRunUO Character Database Thread");
|
||||
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
m_OpSkills = GetUniqueWriter("skills", out m_SkillsPath);
|
||||
m_OpLayers = GetUniqueWriter("layers", out m_LayersPath);
|
||||
m_OpMobiles = GetUniqueWriter("mobiles", out m_MobilesPath);
|
||||
|
||||
m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters");
|
||||
m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters_layers");
|
||||
m_Command.Enqueue("TRUNCATE TABLE myrunuo_characters_skills");
|
||||
}
|
||||
|
||||
m_Command.Enqueue("TRUNCATE TABLE myrunuo_guilds");
|
||||
m_Command.Enqueue("TRUNCATE TABLE myrunuo_guilds_wars");
|
||||
}
|
||||
}
|
||||
|
||||
public void ExecuteNonQuery(string text)
|
||||
{
|
||||
m_Command.Enqueue(text);
|
||||
}
|
||||
|
||||
public void ExecuteNonQuery(string format, params object[] args)
|
||||
{
|
||||
ExecuteNonQuery(string.Format(format, args));
|
||||
}
|
||||
|
||||
public void ExecuteNonQueryIfNull(string select, string insert)
|
||||
{
|
||||
m_Command.Enqueue(new[] { select, insert });
|
||||
}
|
||||
|
||||
private void AppendCharEntity(string input, int charIndex, ref StringBuilder sb, char c)
|
||||
{
|
||||
if (sb == null)
|
||||
{
|
||||
sb = charIndex > 0 ? new StringBuilder(input, 0, charIndex, input.Length + 20) : new StringBuilder(input.Length + 20);
|
||||
}
|
||||
|
||||
sb.Append("&#");
|
||||
sb.Append((int)c);
|
||||
sb.Append(";");
|
||||
}
|
||||
|
||||
private void AppendEntityRef(string input, int charIndex, ref StringBuilder sb, string ent)
|
||||
{
|
||||
if (sb == null)
|
||||
{
|
||||
sb = charIndex > 0 ? new StringBuilder(input, 0, charIndex, input.Length + 20) : new StringBuilder(input.Length + 20);
|
||||
}
|
||||
|
||||
sb.Append(ent);
|
||||
}
|
||||
|
||||
private string SafeString(string input)
|
||||
{
|
||||
if (input == null)
|
||||
return "";
|
||||
|
||||
StringBuilder sb = null;
|
||||
|
||||
for (int i = 0; i < input.Length; ++i)
|
||||
{
|
||||
char c = input[i];
|
||||
|
||||
if (c < 0x20 || c >= 0x7F)
|
||||
AppendCharEntity(input, i, ref sb, c);
|
||||
else
|
||||
switch (c)
|
||||
{
|
||||
case '&':
|
||||
AppendEntityRef(input, i, ref sb, "&");
|
||||
break;
|
||||
case '>':
|
||||
AppendEntityRef(input, i, ref sb, ">");
|
||||
break;
|
||||
case '<':
|
||||
AppendEntityRef(input, i, ref sb, "<");
|
||||
break;
|
||||
case '"':
|
||||
AppendEntityRef(input, i, ref sb, """);
|
||||
break;
|
||||
case '\'':
|
||||
case ':':
|
||||
case '/':
|
||||
case '\\':
|
||||
AppendCharEntity(input, i, ref sb, c);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
sb?.Append(c);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return sb != null ? sb.ToString() : input;
|
||||
}
|
||||
|
||||
public void InsertMobile(Mobile mob)
|
||||
{
|
||||
string guildTitle = mob.GuildTitle;
|
||||
|
||||
if (guildTitle == null || (guildTitle = guildTitle.Trim()).Length == 0)
|
||||
guildTitle = "NULL";
|
||||
else
|
||||
guildTitle = SafeString(guildTitle);
|
||||
|
||||
string notoTitle = SafeString(Titles.ComputeTitle(null, mob));
|
||||
string female = mob.Female ? "1" : "0";
|
||||
|
||||
bool pubBool = mob is PlayerMobile mobile && mobile.PublicMyRunUO;
|
||||
|
||||
string pubString = pubBool ? "1" : "0";
|
||||
|
||||
string guildId = mob.Guild == null ? "NULL" : mob.Guild.Id.ToString();
|
||||
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
m_OpMobiles.Write(LineStart);
|
||||
m_OpMobiles.Write(mob.Serial.Value);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(SafeString(mob.Name));
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(mob.RawStr);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(mob.RawDex);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(mob.RawInt);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(female);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(mob.Kills);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(guildId);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(guildTitle);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(notoTitle);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(mob.Hue);
|
||||
m_OpMobiles.Write(EntrySep);
|
||||
m_OpMobiles.Write(pubString);
|
||||
m_OpMobiles.Write(LineEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteNonQuery(
|
||||
"INSERT INTO myrunuo_characters (char_id, char_name, char_str, char_dex, char_int, char_female, char_counts, char_guild, char_guildtitle, char_nototitle, char_bodyhue, char_public ) VALUES ({0}, '{1}', {2}, {3}, {4}, {5}, {6}, {7}, {8}, '{9}', {10}, {11})",
|
||||
mob.Serial.Value.ToString(), SafeString(mob.Name), mob.RawStr.ToString(), mob.RawDex.ToString(),
|
||||
mob.RawInt.ToString(), female, mob.Kills.ToString(), guildId, guildTitle, notoTitle, mob.Hue.ToString(),
|
||||
pubString);
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertSkills(Mobile mob)
|
||||
{
|
||||
Skills skills = mob.Skills;
|
||||
string serial = mob.Serial.Value.ToString();
|
||||
|
||||
for (int i = 0; i < skills.Length; ++i)
|
||||
{
|
||||
Skill skill = skills[i];
|
||||
|
||||
if (skill.BaseFixedPoint > 0)
|
||||
{
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
m_OpSkills.Write(LineStart);
|
||||
m_OpSkills.Write(serial);
|
||||
m_OpSkills.Write(EntrySep);
|
||||
m_OpSkills.Write(i);
|
||||
m_OpSkills.Write(EntrySep);
|
||||
m_OpSkills.Write(skill.BaseFixedPoint);
|
||||
m_OpSkills.Write(LineEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteNonQuery(
|
||||
"INSERT INTO myrunuo_characters_skills (char_id, skill_id, skill_value) VALUES ({0}, {1}, {2})",
|
||||
serial, i.ToString(), skill.BaseFixedPoint.ToString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void InsertItem(string serial, int index, int itemID, int hue)
|
||||
{
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
m_OpLayers.Write(LineStart);
|
||||
m_OpLayers.Write(serial);
|
||||
m_OpLayers.Write(EntrySep);
|
||||
m_OpLayers.Write(index);
|
||||
m_OpLayers.Write(EntrySep);
|
||||
m_OpLayers.Write(itemID);
|
||||
m_OpLayers.Write(EntrySep);
|
||||
m_OpLayers.Write(hue);
|
||||
m_OpLayers.Write(LineEnd);
|
||||
}
|
||||
else
|
||||
{
|
||||
ExecuteNonQuery(
|
||||
"INSERT INTO myrunuo_characters_layers (char_id, layer_id, item_id, item_hue) VALUES ({0}, {1}, {2}, {3})",
|
||||
serial, index.ToString(), itemID.ToString(), hue.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
public void InsertItems(Mobile mob)
|
||||
{
|
||||
List<Item> items = m_Items;
|
||||
items.AddRange(mob.Items);
|
||||
string serial = mob.Serial.Value.ToString();
|
||||
|
||||
items.Sort(LayerComparer.Instance);
|
||||
|
||||
int index = 0;
|
||||
|
||||
bool hidePants = false;
|
||||
bool alive = mob.Alive;
|
||||
bool hideHair = !alive;
|
||||
|
||||
for (int i = 0; i < items.Count; ++i)
|
||||
{
|
||||
Item item = items[i];
|
||||
|
||||
if (!LayerComparer.IsValid(item))
|
||||
break;
|
||||
|
||||
if (!alive && item.ItemID != 8270)
|
||||
continue;
|
||||
|
||||
if (item.ItemID == 0x1411 || item.ItemID == 0x141A) // plate legs
|
||||
hidePants = true;
|
||||
else if (hidePants && item.Layer == Layer.Pants)
|
||||
continue;
|
||||
|
||||
if (!hideHair && item.Layer == Layer.Helm)
|
||||
hideHair = true;
|
||||
|
||||
InsertItem(serial, index++, item.ItemID, item.Hue);
|
||||
}
|
||||
|
||||
if (mob.FacialHairItemID != 0 && alive)
|
||||
InsertItem(serial, index++, mob.FacialHairItemID, mob.FacialHairHue);
|
||||
|
||||
if (mob.HairItemID != 0 && !hideHair)
|
||||
InsertItem(serial, index, mob.HairItemID, mob.HairHue);
|
||||
|
||||
items.Clear();
|
||||
}
|
||||
|
||||
public void DeleteMobile(Mobile mob)
|
||||
{
|
||||
ExecuteNonQuery("DELETE FROM myrunuo_characters WHERE char_id = {0}", mob.Serial.Value.ToString());
|
||||
ExecuteNonQuery("DELETE FROM myrunuo_characters_skills WHERE char_id = {0}", mob.Serial.Value.ToString());
|
||||
ExecuteNonQuery("DELETE FROM myrunuo_characters_layers WHERE char_id = {0}", mob.Serial.Value.ToString());
|
||||
}
|
||||
|
||||
public StreamWriter GetUniqueWriter(string type, out string filePath)
|
||||
{
|
||||
filePath = Path.Combine(Core.BaseDirectory, $"myrunuodb_{type}.txt")
|
||||
.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
|
||||
try
|
||||
{
|
||||
return new StreamWriter(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
for (int i = 0; i < 100; ++i)
|
||||
try
|
||||
{
|
||||
filePath = Path.Combine(Core.BaseDirectory, $"myrunuodb_{type}_{i}.txt")
|
||||
.Replace(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
|
||||
return new StreamWriter(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public void DumpMobiles(DateTime endTime)
|
||||
{
|
||||
CheckConnection();
|
||||
|
||||
for (int i = m_Index; i < m_List.Count; ++i)
|
||||
{
|
||||
Mobile mob = (Mobile)m_List[i];
|
||||
|
||||
if (mob is PlayerMobile mobile)
|
||||
mobile.ChangedMyRunUO = false;
|
||||
|
||||
if (!mob.Deleted && mob.AccessLevel < Config.HiddenAccessLevel)
|
||||
{
|
||||
if (!Config.LoadDataInFile)
|
||||
DeleteMobile(mob);
|
||||
|
||||
InsertMobile(mob);
|
||||
InsertSkills(mob);
|
||||
InsertItems(mob);
|
||||
}
|
||||
else if (!Config.LoadDataInFile)
|
||||
{
|
||||
DeleteMobile(mob);
|
||||
}
|
||||
|
||||
++m_Index;
|
||||
|
||||
if (DateTime.UtcNow >= endTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_Index == m_List.Count)
|
||||
{
|
||||
m_List.Clear();
|
||||
m_Stage = Stage.CollectingGuilds;
|
||||
m_Index = 0;
|
||||
|
||||
if (Config.LoadDataInFile)
|
||||
{
|
||||
m_OpSkills.Close();
|
||||
m_OpLayers.Close();
|
||||
m_OpMobiles.Close();
|
||||
|
||||
ExecuteNonQuery(
|
||||
"LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'",
|
||||
Config.DatabaseNonLocal ? "LOCAL " : "", m_MobilesPath);
|
||||
ExecuteNonQuery(
|
||||
"LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_skills FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'",
|
||||
Config.DatabaseNonLocal ? "LOCAL " : "", m_SkillsPath);
|
||||
ExecuteNonQuery(
|
||||
"LOAD DATA {0}INFILE '{1}' INTO TABLE myrunuo_characters_layers FIELDS TERMINATED BY ',' ENCLOSED BY '\"' LINES TERMINATED BY '\n'",
|
||||
Config.DatabaseNonLocal ? "LOCAL " : "", m_LayersPath);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void CollectGuilds(DateTime endTime)
|
||||
{
|
||||
m_List.AddRange(BaseGuild.List.Values);
|
||||
m_Stage = Stage.DumpingGuilds;
|
||||
m_Index = 0;
|
||||
}
|
||||
|
||||
public void InsertGuild(Guild guild)
|
||||
{
|
||||
string guildType = "Standard";
|
||||
|
||||
switch (guild.Type)
|
||||
{
|
||||
case GuildType.Chaos:
|
||||
guildType = "Chaos";
|
||||
break;
|
||||
case GuildType.Order:
|
||||
guildType = "Order";
|
||||
break;
|
||||
}
|
||||
|
||||
ExecuteNonQuery(
|
||||
"INSERT INTO myrunuo_guilds (guild_id, guild_name, guild_abbreviation, guild_website, guild_charter, guild_type, guild_wars, guild_members, guild_master) VALUES ({0}, '{1}', {2}, {3}, {4}, '{5}', {6}, {7}, {8})",
|
||||
guild.Id.ToString(), SafeString(guild.Name),
|
||||
guild.Abbreviation == "none" ? "NULL" : "'" + SafeString(guild.Abbreviation) + "'",
|
||||
guild.Website == null ? "NULL" : "'" + SafeString(guild.Website) + "'",
|
||||
guild.Charter == null ? "NULL" : "'" + SafeString(guild.Charter) + "'", guildType,
|
||||
guild.Enemies.Count.ToString(), guild.Members.Count.ToString(), guild.Leader.Serial.Value.ToString());
|
||||
}
|
||||
|
||||
public void InsertWars(Guild guild)
|
||||
{
|
||||
List<Guild> wars = guild.Enemies;
|
||||
|
||||
string ourId = guild.Id.ToString();
|
||||
|
||||
for (int i = 0; i < wars.Count; ++i)
|
||||
{
|
||||
Guild them = wars[i];
|
||||
string theirId = them.Id.ToString();
|
||||
|
||||
ExecuteNonQueryIfNull(
|
||||
string.Format(
|
||||
"SELECT guild_1 FROM myrunuo_guilds_wars WHERE (guild_1={0} AND guild_2={1}) OR (guild_1={1} AND guild_2={0})",
|
||||
ourId, theirId),
|
||||
$"INSERT INTO myrunuo_guilds_wars (guild_1, guild_2) VALUES ({ourId}, {theirId})");
|
||||
}
|
||||
}
|
||||
|
||||
public void DumpGuilds(DateTime endTime)
|
||||
{
|
||||
CheckConnection();
|
||||
|
||||
for (int i = m_Index; i < m_List.Count; ++i)
|
||||
{
|
||||
Guild guild = (Guild)m_List[i];
|
||||
|
||||
if (!guild.Disbanded)
|
||||
{
|
||||
InsertGuild(guild);
|
||||
InsertWars(guild);
|
||||
}
|
||||
|
||||
++m_Index;
|
||||
|
||||
if (DateTime.UtcNow >= endTime)
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_Index == m_List.Count)
|
||||
{
|
||||
m_List.Clear();
|
||||
m_Stage = Stage.Complete;
|
||||
m_Index = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private enum Stage
|
||||
{
|
||||
CollectingMobiles,
|
||||
DumpingMobiles,
|
||||
CollectingGuilds,
|
||||
DumpingGuilds,
|
||||
Complete
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Commands;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.MyRunUO
|
||||
{
|
||||
public class MyRunUOStatus
|
||||
{
|
||||
private static DatabaseCommandQueue m_Command;
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (Config.Enabled)
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromSeconds(20.0), Config.StatusUpdateInterval, Begin);
|
||||
|
||||
CommandSystem.Register("UpdateWebStatus", AccessLevel.Administrator, UpdateWebStatus_OnCommand);
|
||||
}
|
||||
}
|
||||
|
||||
[Usage("UpdateWebStatus")]
|
||||
[Description("Starts the process of updating the MyRunUO online status database.")]
|
||||
public static void UpdateWebStatus_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
if (m_Command == null || m_Command.HasCompleted)
|
||||
{
|
||||
Begin();
|
||||
e.Mobile.SendMessage("Web status update process has been started.");
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.SendMessage("Web status database is already being updated.");
|
||||
}
|
||||
}
|
||||
|
||||
public static void Begin()
|
||||
{
|
||||
if (m_Command?.HasCompleted == false)
|
||||
return;
|
||||
|
||||
Console.WriteLine("MyRunUO: Updating status database");
|
||||
|
||||
try
|
||||
{
|
||||
m_Command = new DatabaseCommandQueue("MyRunUO: Status database updated in {0:F1} seconds",
|
||||
"MyRunUO Status Database Thread");
|
||||
|
||||
m_Command.Enqueue("DELETE FROM myrunuo_status");
|
||||
|
||||
List<NetState> online = NetState.Instances;
|
||||
|
||||
for (int i = 0; i < online.Count; ++i)
|
||||
{
|
||||
NetState ns = online[i];
|
||||
Mobile mob = ns.Mobile;
|
||||
|
||||
if (mob != null)
|
||||
m_Command.Enqueue(
|
||||
$"INSERT INTO myrunuo_status (char_id) VALUES ({mob.Serial.Value.ToString()})");
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("MyRunUO: Error updating status database");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
|
||||
m_Command?.Enqueue(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,307 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public enum BarGraphRenderMode
|
||||
{
|
||||
Bars,
|
||||
Lines
|
||||
}
|
||||
|
||||
public class BarGraph : Chart
|
||||
{
|
||||
public BarGraph(string name, string fileName, int ticks, string xTitle, string yTitle, BarGraphRenderMode rm)
|
||||
{
|
||||
m_Name = name;
|
||||
m_FileName = fileName;
|
||||
Ticks = ticks;
|
||||
this.xTitle = xTitle;
|
||||
this.yTitle = yTitle;
|
||||
RenderMode = rm;
|
||||
}
|
||||
|
||||
private BarGraph()
|
||||
{
|
||||
}
|
||||
|
||||
public int Ticks{ get; set; }
|
||||
|
||||
public BarGraphRenderMode RenderMode{ get; set; }
|
||||
|
||||
public string xTitle{ get; set; }
|
||||
|
||||
public string yTitle{ get; set; }
|
||||
|
||||
public int FontSize{ get; set; } = 7;
|
||||
|
||||
public int Interval{ get; set; } = 1;
|
||||
|
||||
public BarRegion[] Regions{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
base.SerializeAttributes(op);
|
||||
|
||||
op.SetInt32("t", Ticks);
|
||||
op.SetInt32("r", (int)RenderMode);
|
||||
|
||||
op.SetString("x", xTitle);
|
||||
op.SetString("y", yTitle);
|
||||
|
||||
op.SetInt32("s", FontSize);
|
||||
op.SetInt32("i", Interval);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
base.DeserializeAttributes(ip);
|
||||
|
||||
Ticks = ip.GetInt32("t");
|
||||
RenderMode = (BarGraphRenderMode)ip.GetInt32("r");
|
||||
|
||||
xTitle = Utility.Intern(ip.GetString("x"));
|
||||
yTitle = Utility.Intern(ip.GetString("y"));
|
||||
|
||||
FontSize = ip.GetInt32("s");
|
||||
Interval = ip.GetInt32("i");
|
||||
}
|
||||
|
||||
public static int LookupReportValue(Snapshot ss, string reportName, string valueName)
|
||||
{
|
||||
for (int j = 0; j < ss.Children.Count; ++j)
|
||||
{
|
||||
if (!(ss.Children[j] is Report report) || report.Name != reportName)
|
||||
continue;
|
||||
|
||||
for (int k = 0; k < report.Items.Count; ++k)
|
||||
{
|
||||
ReportItem item = report.Items[k];
|
||||
|
||||
if (item.Values[0].Value == valueName)
|
||||
return Utility.ToInt32(item.Values[1].Value);
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public static BarGraph DailyAverage(SnapshotHistory history, string reportName, string valueName)
|
||||
{
|
||||
int[] totals = new int[24];
|
||||
int[] counts = new int[24];
|
||||
|
||||
int min = history.Snapshots.Count - 7 * 24; // averages over one week
|
||||
|
||||
if (min < 0)
|
||||
min = 0;
|
||||
|
||||
for (int i = min; i < history.Snapshots.Count; ++i)
|
||||
{
|
||||
Snapshot ss = history.Snapshots[i];
|
||||
|
||||
int val = LookupReportValue(ss, reportName, valueName);
|
||||
|
||||
if (val == -1)
|
||||
continue;
|
||||
|
||||
int hour = ss.TimeStamp.TimeOfDay.Hours;
|
||||
|
||||
totals[hour] += val;
|
||||
counts[hour]++;
|
||||
}
|
||||
|
||||
BarGraph barGraph = new BarGraph("Hourly average " + valueName, "graphs_" + valueName.ToLower() + "_avg", 10,
|
||||
"Time", valueName, BarGraphRenderMode.Lines);
|
||||
|
||||
barGraph.FontSize = 6;
|
||||
|
||||
for (int i = 7; i <= totals.Length + 7; ++i)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (counts[i % totals.Length] == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length];
|
||||
|
||||
int realHours = i % totals.Length;
|
||||
int hours;
|
||||
|
||||
if (realHours == 0)
|
||||
hours = 12;
|
||||
else if (realHours > 12)
|
||||
hours = realHours - 12;
|
||||
else
|
||||
hours = realHours;
|
||||
|
||||
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
||||
}
|
||||
|
||||
return barGraph;
|
||||
}
|
||||
|
||||
public static BarGraph Growth(SnapshotHistory history, string reportName, string valueName)
|
||||
{
|
||||
BarGraph barGraph = new BarGraph("Growth of " + valueName + " over time",
|
||||
"graphs_" + valueName.ToLower() + "_growth", 10, "Time", valueName, BarGraphRenderMode.Lines);
|
||||
|
||||
barGraph.FontSize = 6;
|
||||
barGraph.Interval = 7;
|
||||
|
||||
DateTime startPeriod = history.Snapshots[0].TimeStamp.Date + TimeSpan.FromDays(1.0);
|
||||
DateTime endPeriod = history.Snapshots[history.Snapshots.Count - 1].TimeStamp.Date;
|
||||
|
||||
List<BarRegion> regions = new List<BarRegion>();
|
||||
|
||||
DateTime curDate = DateTime.MinValue;
|
||||
int curPeak = -1;
|
||||
int curLow = 1000;
|
||||
int curTotl = 0;
|
||||
int curCont = 0;
|
||||
int curValu;
|
||||
|
||||
for (int i = 0; i < history.Snapshots.Count; ++i)
|
||||
{
|
||||
Snapshot ss = history.Snapshots[i];
|
||||
DateTime timeStamp = ss.TimeStamp;
|
||||
|
||||
if (timeStamp < startPeriod || timeStamp >= endPeriod)
|
||||
continue;
|
||||
|
||||
int val = LookupReportValue(ss, reportName, valueName);
|
||||
|
||||
if (val == -1)
|
||||
continue;
|
||||
|
||||
DateTime thisDate = timeStamp.Date;
|
||||
|
||||
if (curDate == DateTime.MinValue)
|
||||
curDate = thisDate;
|
||||
|
||||
curCont++;
|
||||
curTotl += val;
|
||||
curValu = curTotl / curCont;
|
||||
|
||||
if (curDate != thisDate && curValu >= 0)
|
||||
{
|
||||
string mnthName = thisDate.ToString("MMMM");
|
||||
|
||||
if (regions.Count == 0)
|
||||
{
|
||||
regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, mnthName));
|
||||
}
|
||||
else
|
||||
{
|
||||
BarRegion region = regions[regions.Count - 1];
|
||||
|
||||
if (region.m_Name == mnthName)
|
||||
region.m_RangeTo = barGraph.Items.Count;
|
||||
else
|
||||
regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, mnthName));
|
||||
}
|
||||
|
||||
barGraph.Items.Add(thisDate.Day.ToString(), curValu);
|
||||
|
||||
curPeak = val;
|
||||
curLow = val;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (val > curPeak)
|
||||
curPeak = val;
|
||||
|
||||
if (val > 0 && val < curLow)
|
||||
curLow = val;
|
||||
}
|
||||
|
||||
curDate = thisDate;
|
||||
}
|
||||
|
||||
barGraph.Regions = regions.ToArray();
|
||||
|
||||
return barGraph;
|
||||
}
|
||||
|
||||
public static BarGraph OverTime(SnapshotHistory history, string reportName, string valueName, int step, int max,
|
||||
int ival)
|
||||
{
|
||||
BarGraph barGraph = new BarGraph(valueName + " over time", "graphs_" + valueName.ToLower() + "_ot", 10, "Time",
|
||||
valueName, BarGraphRenderMode.Lines);
|
||||
|
||||
TimeSpan ts = TimeSpan.FromHours(max * step - 0.5);
|
||||
|
||||
DateTime mostRecent = history.Snapshots[history.Snapshots.Count - 1].TimeStamp;
|
||||
DateTime minTime = mostRecent - ts;
|
||||
|
||||
barGraph.FontSize = 6;
|
||||
barGraph.Interval = ival;
|
||||
|
||||
List<BarRegion> regions = new List<BarRegion>();
|
||||
|
||||
for (int i = 0; i < history.Snapshots.Count; ++i)
|
||||
{
|
||||
Snapshot ss = history.Snapshots[i];
|
||||
DateTime timeStamp = ss.TimeStamp;
|
||||
|
||||
if (timeStamp < minTime)
|
||||
continue;
|
||||
|
||||
if (i % step != 0)
|
||||
continue;
|
||||
|
||||
int val = LookupReportValue(ss, reportName, valueName);
|
||||
|
||||
if (val == -1)
|
||||
continue;
|
||||
|
||||
int realHours = timeStamp.TimeOfDay.Hours;
|
||||
int hours;
|
||||
|
||||
if (realHours == 0)
|
||||
hours = 12;
|
||||
else if (realHours > 12)
|
||||
hours = realHours - 12;
|
||||
else
|
||||
hours = realHours;
|
||||
|
||||
string dayName = timeStamp.DayOfWeek.ToString();
|
||||
|
||||
if (regions.Count == 0)
|
||||
{
|
||||
regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, dayName));
|
||||
}
|
||||
else
|
||||
{
|
||||
BarRegion region = regions[regions.Count - 1];
|
||||
|
||||
if (region.m_Name == dayName)
|
||||
region.m_RangeTo = barGraph.Items.Count;
|
||||
else
|
||||
regions.Add(new BarRegion(barGraph.Items.Count, barGraph.Items.Count, dayName));
|
||||
}
|
||||
|
||||
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
||||
}
|
||||
|
||||
barGraph.Regions = regions.ToArray();
|
||||
|
||||
return barGraph;
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("bg", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new BarGraph();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,52 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public abstract class Chart : PersistableObject
|
||||
{
|
||||
protected string m_FileName;
|
||||
protected ChartItemCollection m_Items;
|
||||
protected string m_Name;
|
||||
|
||||
public Chart()
|
||||
{
|
||||
m_Items = new ChartItemCollection();
|
||||
}
|
||||
|
||||
public string Name
|
||||
{
|
||||
get => m_Name;
|
||||
set => m_Name = value;
|
||||
}
|
||||
|
||||
public string FileName
|
||||
{
|
||||
get => m_FileName;
|
||||
set => m_FileName = value;
|
||||
}
|
||||
|
||||
public ChartItemCollection Items => m_Items;
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetString("n", m_Name);
|
||||
op.SetString("f", m_FileName);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
m_Name = Utility.Intern(ip.GetString("n"));
|
||||
m_FileName = Utility.Intern(ip.GetString("f"));
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < m_Items.Count; ++i)
|
||||
m_Items[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
m_Items.Add(ip.GetChild() as ChartItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class ChartItem : PersistableObject
|
||||
{
|
||||
private ChartItem()
|
||||
{
|
||||
}
|
||||
|
||||
public ChartItem(string name, int value)
|
||||
{
|
||||
Name = name;
|
||||
Value = value;
|
||||
}
|
||||
|
||||
public string Name{ get; set; }
|
||||
|
||||
public int Value{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetString("n", Name);
|
||||
op.SetInt32("v", Value);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
Name = Utility.Intern(ip.GetString("n"));
|
||||
Value = ip.GetInt32("v");
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("ci", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new ChartItem();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.ChartItem.
|
||||
/// </summary>
|
||||
public class ChartItemCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.ChartItem at a specific position in the ChartItemCollection.
|
||||
/// </summary>
|
||||
public ChartItem this[int index]
|
||||
{
|
||||
get => (ChartItem)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(string name, int value)
|
||||
{
|
||||
return Add(new ChartItem(name, value));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.ChartItem entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ChartItem instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(ChartItem value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.ChartItem instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ChartItem instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.ChartItem instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(ChartItem value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.ChartItem instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ChartItem instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.ChartItem instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(ChartItem value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.ChartItem instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.ChartItem instance to remove.</param>
|
||||
public void Remove(ChartItem value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.ChartItem instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.ChartItem's enumerator.</returns>
|
||||
public new ChartItemCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ChartItemCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.ChartItem instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.ChartItem instance to insert.</param>
|
||||
public void Insert(int index, ChartItem value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.ChartItem.
|
||||
/// </summary>
|
||||
public class ChartItemCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ChartItemCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private ChartItem _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ChartItemCollectionEnumerator(ChartItemCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.ChartItem object in the enumerated ChartItemCollection currently indexed by this instance.
|
||||
/// </summary>
|
||||
public ChartItem Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class PieChart : Chart
|
||||
{
|
||||
public PieChart(string name, string fileName, bool showPercents)
|
||||
{
|
||||
m_Name = name;
|
||||
m_FileName = fileName;
|
||||
ShowPercents = showPercents;
|
||||
}
|
||||
|
||||
private PieChart()
|
||||
{
|
||||
}
|
||||
|
||||
public bool ShowPercents{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
base.SerializeAttributes(op);
|
||||
|
||||
op.SetBoolean("p", ShowPercents);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
base.DeserializeAttributes(ip);
|
||||
|
||||
ShowPercents = ip.GetBoolean("p");
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("pc", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new PieChart();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class ItemValue : PersistableObject
|
||||
{
|
||||
private string m_Value;
|
||||
|
||||
private ItemValue()
|
||||
{
|
||||
}
|
||||
|
||||
public ItemValue(string value) : this(value, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ItemValue(string value, string format)
|
||||
{
|
||||
m_Value = value;
|
||||
Format = format;
|
||||
}
|
||||
|
||||
public string Value
|
||||
{
|
||||
get => m_Value;
|
||||
set => m_Value = value;
|
||||
}
|
||||
|
||||
public string Format{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetString("v", m_Value);
|
||||
op.SetString("f", Format);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
m_Value = ip.GetString("v");
|
||||
Format = Utility.Intern(ip.GetString("f"));
|
||||
|
||||
if (Format == null)
|
||||
Utility.Intern(ref m_Value);
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("iv", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new ItemValue();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,192 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.ItemValue.
|
||||
/// </summary>
|
||||
public class ItemValueCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.ItemValue at a specific position in the ItemValueCollection.
|
||||
/// </summary>
|
||||
public ItemValue this[int index]
|
||||
{
|
||||
get => (ItemValue)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(string value)
|
||||
{
|
||||
return Add(new ItemValue(value));
|
||||
}
|
||||
|
||||
public int Add(string value, string format)
|
||||
{
|
||||
return Add(new ItemValue(value, format));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.ItemValue entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ItemValue instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(ItemValue value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.ItemValue instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ItemValue instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.ItemValue instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(ItemValue value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.ItemValue instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ItemValue instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.ItemValue instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(ItemValue value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.ItemValue instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.ItemValue instance to remove.</param>
|
||||
public void Remove(ItemValue value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.ItemValue instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.ItemValue's enumerator.</returns>
|
||||
public new ItemValueCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ItemValueCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.ItemValue instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.ItemValue instance to insert.</param>
|
||||
public void Insert(int index, ItemValue value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.ItemValue.
|
||||
/// </summary>
|
||||
public class ItemValueCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ItemValueCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private ItemValue _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ItemValueCollectionEnumerator(ItemValueCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.ItemValue object in the enumerated ItemValueCollection currently indexed by this instance.
|
||||
/// </summary>
|
||||
public ItemValue Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class Report : PersistableObject
|
||||
{
|
||||
private Report() : this(null, null)
|
||||
{
|
||||
}
|
||||
|
||||
public Report(string name, string width)
|
||||
{
|
||||
Name = name;
|
||||
Width = width;
|
||||
Columns = new ReportColumnCollection();
|
||||
Items = new ReportItemCollection();
|
||||
}
|
||||
|
||||
public string Name{ get; set; }
|
||||
|
||||
public string Width{ get; set; }
|
||||
|
||||
public ReportColumnCollection Columns{ get; }
|
||||
|
||||
public ReportItemCollection Items{ get; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetString("n", Name);
|
||||
op.SetString("w", Width);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
Name = Utility.Intern(ip.GetString("n"));
|
||||
Width = Utility.Intern(ip.GetString("w"));
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < Columns.Count; ++i)
|
||||
Columns[i].Serialize(op);
|
||||
|
||||
for (int i = 0; i < Items.Count; ++i)
|
||||
Items[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
{
|
||||
PersistableObject child = ip.GetChild();
|
||||
|
||||
if (child is ReportColumn column)
|
||||
Columns.Add(column);
|
||||
else if (child is ReportItem item)
|
||||
Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("rp", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new Report();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class ReportColumn : PersistableObject
|
||||
{
|
||||
private ReportColumn()
|
||||
{
|
||||
}
|
||||
|
||||
public ReportColumn(string width, string align) : this(width, align, null)
|
||||
{
|
||||
}
|
||||
|
||||
public ReportColumn(string width, string align, string name)
|
||||
{
|
||||
Width = width;
|
||||
Align = align;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public string Width{ get; set; }
|
||||
|
||||
public string Align{ get; set; }
|
||||
|
||||
public string Name{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetString("w", Width);
|
||||
op.SetString("a", Align);
|
||||
op.SetString("n", Name);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
Width = Utility.Intern(ip.GetString("w"));
|
||||
Align = Utility.Intern(ip.GetString("a"));
|
||||
Name = Utility.Intern(ip.GetString("n"));
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("rc", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new ReportColumn();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,193 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.ReportColumn.
|
||||
/// </summary>
|
||||
public class ReportColumnCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.ReportColumn at a specific position in the ReportColumnCollection.
|
||||
/// </summary>
|
||||
public ReportColumn this[int index]
|
||||
{
|
||||
get => (ReportColumn)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(string width, string align)
|
||||
{
|
||||
return Add(new ReportColumn(width, align));
|
||||
}
|
||||
|
||||
public int Add(string width, string align, string name)
|
||||
{
|
||||
return Add(new ReportColumn(width, align, name));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.ReportColumn entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportColumn instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(ReportColumn value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.ReportColumn instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportColumn instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.ReportColumn instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(ReportColumn value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.ReportColumn instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportColumn instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.ReportColumn instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(ReportColumn value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.ReportColumn instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.ReportColumn instance to remove.</param>
|
||||
public void Remove(ReportColumn value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportColumn instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.ReportColumn's enumerator.</returns>
|
||||
public new ReportColumnCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ReportColumnCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.ReportColumn instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.ReportColumn instance to insert.</param>
|
||||
public void Insert(int index, ReportColumn value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.ReportColumn.
|
||||
/// </summary>
|
||||
public class ReportColumnCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ReportColumnCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private ReportColumn _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ReportColumnCollectionEnumerator(ReportColumnCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.ReportColumn object in the enumerated ReportColumnCollection currently indexed by this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public ReportColumn Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class ReportItem : PersistableObject
|
||||
{
|
||||
public ReportItem()
|
||||
{
|
||||
Values = new ItemValueCollection();
|
||||
}
|
||||
|
||||
public ItemValueCollection Values{ get; }
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < Values.Count; ++i)
|
||||
Values[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
Values.Add(ip.GetChild() as ItemValue);
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("ri", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new ReportItem();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.ReportItem.
|
||||
/// </summary>
|
||||
public class ReportItemCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.ReportItem at a specific position in the ReportItemCollection.
|
||||
/// </summary>
|
||||
public ReportItem this[int index]
|
||||
{
|
||||
get => (ReportItem)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(string name, object value)
|
||||
{
|
||||
return Add(name, value, null);
|
||||
}
|
||||
|
||||
public int Add(string name, object value, string format)
|
||||
{
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(name);
|
||||
item.Values.Add(value == null ? "" : value.ToString(), format);
|
||||
|
||||
return Add(item);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.ReportItem entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportItem instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(ReportItem value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.ReportItem instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportItem instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.ReportItem instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(ReportItem value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.ReportItem instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ReportItem instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.ReportItem instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(ReportItem value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.ReportItem instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.ReportItem instance to remove.</param>
|
||||
public void Remove(ReportItem value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.ReportItem instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.ReportItem's enumerator.</returns>
|
||||
public new ReportItemCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ReportItemCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.ReportItem instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.ReportItem instance to insert.</param>
|
||||
public void Insert(int index, ReportItem value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.ReportItem.
|
||||
/// </summary>
|
||||
public class ReportItemCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ReportItemCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private ReportItem _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ReportItemCollectionEnumerator(ReportItemCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.ReportItem object in the enumerated ReportItemCollection currently indexed by this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public ReportItem Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class Snapshot : PersistableObject
|
||||
{
|
||||
public Snapshot()
|
||||
{
|
||||
Children = new ObjectCollection();
|
||||
}
|
||||
|
||||
public DateTime TimeStamp{ get; set; }
|
||||
|
||||
public ObjectCollection Children{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetDateTime("t", TimeStamp);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
TimeStamp = ip.GetDateTime("t");
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < Children.Count; ++i)
|
||||
Children[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
Children.Add(ip.GetChild());
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("ss", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new Snapshot();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.Snapshot.
|
||||
/// </summary>
|
||||
public class SnapshotCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.Snapshot at a specific position in the SnapshotCollection.
|
||||
/// </summary>
|
||||
public Snapshot this[int index]
|
||||
{
|
||||
get => (Snapshot)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.Snapshot entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.Snapshot instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(Snapshot value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.Snapshot instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.Snapshot instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.Snapshot instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(Snapshot value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.Snapshot instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.Snapshot instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.Snapshot instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(Snapshot value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.Snapshot instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.Snapshot instance to remove.</param>
|
||||
public void Remove(Snapshot value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.Snapshot instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.Snapshot's enumerator.</returns>
|
||||
public new SnapshotCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new SnapshotCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.Snapshot instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.Snapshot instance to insert.</param>
|
||||
public void Insert(int index, Snapshot value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.Snapshot.
|
||||
/// </summary>
|
||||
public class SnapshotCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private SnapshotCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private Snapshot _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal SnapshotCollectionEnumerator(SnapshotCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.Snapshot object in the enumerated SnapshotCollection currently indexed by this instance.
|
||||
/// </summary>
|
||||
public Snapshot Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using System.IO;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class SnapshotHistory : PersistableObject
|
||||
{
|
||||
public SnapshotHistory()
|
||||
{
|
||||
Snapshots = new SnapshotCollection();
|
||||
}
|
||||
|
||||
public SnapshotCollection Snapshots{ get; set; }
|
||||
|
||||
public void Save()
|
||||
{
|
||||
string path = Path.Combine(Core.BaseDirectory, "reportHistory.xml");
|
||||
PersistanceWriter pw = new XmlPersistanceWriter(path, "Stats");
|
||||
|
||||
pw.WriteDocument(this);
|
||||
|
||||
pw.Close();
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
string path = Path.Combine(Core.BaseDirectory, "reportHistory.xml");
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
PersistanceReader pr = new XmlPersistanceReader(path, "Stats");
|
||||
|
||||
pr.ReadDocument(this);
|
||||
|
||||
pr.Close();
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < Snapshots.Count; ++i)
|
||||
Snapshots[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
Snapshots.Add(ip.GetChild() as Snapshot);
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("sh", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new SnapshotHistory();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,93 +0,0 @@
|
|||
using System;
|
||||
using Server.Accounting;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public abstract class BaseInfo : IComparable<BaseInfo>
|
||||
{
|
||||
private string m_Display;
|
||||
|
||||
public BaseInfo(string account)
|
||||
{
|
||||
Account = account;
|
||||
Pages = new PageInfoCollection();
|
||||
}
|
||||
|
||||
public static TimeSpan SortRange{ get; set; }
|
||||
|
||||
public string Account{ get; set; }
|
||||
|
||||
public PageInfoCollection Pages{ get; set; }
|
||||
|
||||
public string Display
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Display != null)
|
||||
return m_Display;
|
||||
|
||||
if (Account != null)
|
||||
{
|
||||
IAccount acct = Accounts.GetAccount(Account);
|
||||
|
||||
if (acct != null)
|
||||
{
|
||||
Mobile mob = null;
|
||||
|
||||
for (int i = 0; i < acct.Length; ++i)
|
||||
{
|
||||
Mobile check = acct[i];
|
||||
|
||||
if (check != null && (mob == null || check.AccessLevel > mob.AccessLevel))
|
||||
mob = check;
|
||||
}
|
||||
|
||||
if (mob?.Name != null && mob.Name.Length > 0)
|
||||
return m_Display = mob.Name;
|
||||
}
|
||||
}
|
||||
|
||||
return m_Display = Account;
|
||||
}
|
||||
}
|
||||
|
||||
public int CompareTo(BaseInfo cmp)
|
||||
{
|
||||
int v = cmp?.GetPageCount(cmp is StaffInfo ? PageResolution.Handled : PageResolution.None,
|
||||
DateTime.UtcNow - SortRange, DateTime.UtcNow) ?? 0
|
||||
- GetPageCount(this is StaffInfo ? PageResolution.Handled : PageResolution.None,
|
||||
DateTime.UtcNow - SortRange, DateTime.UtcNow);
|
||||
|
||||
return v == 0 ? string.Compare(Display, cmp.Display) : v;
|
||||
}
|
||||
|
||||
public int GetPageCount(PageResolution res, DateTime min, DateTime max)
|
||||
{
|
||||
return StaffHistory.GetPageCount(Pages, res, min, max);
|
||||
}
|
||||
|
||||
public void Register(PageInfo page)
|
||||
{
|
||||
Pages.Add(page);
|
||||
}
|
||||
|
||||
public void Unregister(PageInfo page)
|
||||
{
|
||||
Pages.Remove(page);
|
||||
}
|
||||
}
|
||||
|
||||
public class StaffInfo : BaseInfo
|
||||
{
|
||||
public StaffInfo(string account) : base(account)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public class UserInfo : BaseInfo
|
||||
{
|
||||
public UserInfo(string account) : base(account)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,233 +0,0 @@
|
|||
using System;
|
||||
using Server.Accounting;
|
||||
using Server.Engines.Help;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public enum PageResolution
|
||||
{
|
||||
None,
|
||||
Handled,
|
||||
Deleted,
|
||||
Logged,
|
||||
Canceled
|
||||
}
|
||||
|
||||
public class PageInfo : PersistableObject
|
||||
{
|
||||
private StaffHistory m_History;
|
||||
private StaffInfo m_Resolver;
|
||||
private UserInfo m_Sender;
|
||||
|
||||
private string m_SentBy;
|
||||
|
||||
public PageInfo()
|
||||
{
|
||||
Responses = new ResponseInfoCollection();
|
||||
}
|
||||
|
||||
public PageInfo(PageEntry entry)
|
||||
{
|
||||
PageType = entry.Type;
|
||||
|
||||
TimeSent = entry.Sent;
|
||||
m_SentBy = GetAccount(entry.Sender);
|
||||
|
||||
Message = entry.Message;
|
||||
Responses = new ResponseInfoCollection();
|
||||
}
|
||||
|
||||
public StaffInfo Resolver
|
||||
{
|
||||
get => m_Resolver;
|
||||
set
|
||||
{
|
||||
if (m_Resolver == value)
|
||||
return;
|
||||
|
||||
lock (StaffHistory.RenderLock)
|
||||
{
|
||||
m_Resolver?.Unregister(this);
|
||||
|
||||
m_Resolver = value;
|
||||
|
||||
m_Resolver?.Register(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo Sender
|
||||
{
|
||||
get => m_Sender;
|
||||
set
|
||||
{
|
||||
if (m_Sender == value)
|
||||
return;
|
||||
|
||||
lock (StaffHistory.RenderLock)
|
||||
{
|
||||
m_Sender?.Unregister(this);
|
||||
|
||||
m_Sender = value;
|
||||
|
||||
m_Sender?.Register(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StaffHistory History
|
||||
{
|
||||
get => m_History;
|
||||
set
|
||||
{
|
||||
if (m_History == value)
|
||||
return;
|
||||
|
||||
if (m_History != null)
|
||||
{
|
||||
Sender = null;
|
||||
Resolver = null;
|
||||
}
|
||||
|
||||
m_History = value;
|
||||
|
||||
if (m_History != null)
|
||||
{
|
||||
Sender = m_History.GetUserInfo(m_SentBy);
|
||||
UpdateResolver();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public PageType PageType{ get; set; }
|
||||
|
||||
public PageResolution Resolution{ get; private set; }
|
||||
|
||||
public DateTime TimeSent{ get; set; }
|
||||
|
||||
public DateTime TimeResolved{ get; private set; }
|
||||
|
||||
public string SentBy
|
||||
{
|
||||
get => m_SentBy;
|
||||
set
|
||||
{
|
||||
m_SentBy = value;
|
||||
|
||||
if (m_History != null)
|
||||
Sender = m_History.GetUserInfo(m_SentBy);
|
||||
}
|
||||
}
|
||||
|
||||
public string ResolvedBy{ get; private set; }
|
||||
|
||||
public string Message{ get; set; }
|
||||
|
||||
public ResponseInfoCollection Responses{ get; set; }
|
||||
|
||||
public void UpdateResolver()
|
||||
{
|
||||
PageResolution res = GetResolution(out string resolvedBy, out DateTime timeResolved);
|
||||
|
||||
if (m_History != null && IsStaffResolution(res))
|
||||
Resolver = m_History.GetStaffInfo(resolvedBy);
|
||||
else
|
||||
Resolver = null;
|
||||
|
||||
ResolvedBy = resolvedBy;
|
||||
TimeResolved = timeResolved;
|
||||
Resolution = res;
|
||||
}
|
||||
|
||||
public bool IsStaffResolution(PageResolution res)
|
||||
{
|
||||
return res == PageResolution.Handled;
|
||||
}
|
||||
|
||||
public static PageResolution ResFromResp(string resp)
|
||||
{
|
||||
switch (resp)
|
||||
{
|
||||
case "[Handled]": return PageResolution.Handled;
|
||||
case "[Deleting]": return PageResolution.Deleted;
|
||||
case "[Logout]": return PageResolution.Logged;
|
||||
case "[Canceled]": return PageResolution.Canceled;
|
||||
}
|
||||
|
||||
return PageResolution.None;
|
||||
}
|
||||
|
||||
public PageResolution GetResolution(out string resolvedBy, out DateTime timeResolved)
|
||||
{
|
||||
for (int i = Responses.Count - 1; i >= 0; --i)
|
||||
{
|
||||
ResponseInfo resp = Responses[i];
|
||||
PageResolution res = ResFromResp(resp.Message);
|
||||
|
||||
if (res != PageResolution.None)
|
||||
{
|
||||
resolvedBy = resp.SentBy;
|
||||
timeResolved = resp.TimeStamp;
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
resolvedBy = m_SentBy;
|
||||
timeResolved = TimeSent;
|
||||
return PageResolution.None;
|
||||
}
|
||||
|
||||
public static string GetAccount(Mobile mob)
|
||||
{
|
||||
return mob?.Account is Account acct ? acct.Username : null;
|
||||
}
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetInt32("p", (int)PageType);
|
||||
|
||||
op.SetDateTime("ts", TimeSent);
|
||||
op.SetString("s", m_SentBy);
|
||||
|
||||
op.SetString("m", Message);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
PageType = (PageType)ip.GetInt32("p");
|
||||
|
||||
TimeSent = ip.GetDateTime("ts");
|
||||
m_SentBy = ip.GetString("s");
|
||||
|
||||
Message = ip.GetString("m");
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
for (int i = 0; i < Responses.Count; ++i)
|
||||
Responses[i].Serialize(op);
|
||||
}
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
while (ip.HasChild)
|
||||
Responses.Add(ip.GetChild() as ResponseInfo);
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("pi", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new PageInfo();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,182 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.PageInfo.
|
||||
/// </summary>
|
||||
public class PageInfoCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.PageInfo at a specific position in the PageInfoCollection.
|
||||
/// </summary>
|
||||
public PageInfo this[int index]
|
||||
{
|
||||
get => (PageInfo)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.PageInfo entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PageInfo instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(PageInfo value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.PageInfo instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PageInfo instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.PageInfo instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(PageInfo value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.PageInfo instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PageInfo instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.PageInfo instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(PageInfo value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.PageInfo instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.PageInfo instance to remove.</param>
|
||||
public void Remove(PageInfo value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.PageInfo instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.PageInfo's enumerator.</returns>
|
||||
public new PageInfoCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new PageInfoCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.PageInfo instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.PageInfo instance to insert.</param>
|
||||
public void Insert(int index, PageInfo value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.PageInfo.
|
||||
/// </summary>
|
||||
public class PageInfoCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private PageInfoCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private PageInfo _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal PageInfoCollectionEnumerator(PageInfoCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.PageInfo object in the enumerated PageInfoCollection currently indexed by this instance.
|
||||
/// </summary>
|
||||
public PageInfo Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class QueueStatus : PersistableObject
|
||||
{
|
||||
public QueueStatus()
|
||||
{
|
||||
}
|
||||
|
||||
public QueueStatus(int count)
|
||||
{
|
||||
TimeStamp = DateTime.UtcNow;
|
||||
Count = count;
|
||||
}
|
||||
|
||||
public DateTime TimeStamp{ get; set; }
|
||||
|
||||
public int Count{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetDateTime("t", TimeStamp);
|
||||
op.SetInt32("c", Count);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
TimeStamp = ip.GetDateTime("t");
|
||||
Count = ip.GetInt32("c");
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("qs", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new QueueStatus();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.QueueStatus.
|
||||
/// </summary>
|
||||
public class QueueStatusCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.QueueStatus at a specific position in the QueueStatusCollection.
|
||||
/// </summary>
|
||||
public QueueStatus this[int index]
|
||||
{
|
||||
get => (QueueStatus)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.QueueStatus entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.QueueStatus instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(QueueStatus value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.QueueStatus instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.QueueStatus instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.QueueStatus instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(QueueStatus value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.QueueStatus instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.QueueStatus instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.QueueStatus instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(QueueStatus value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.QueueStatus instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.QueueStatus instance to remove.</param>
|
||||
public void Remove(QueueStatus value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.QueueStatus instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.QueueStatus's enumerator.</returns>
|
||||
public new QueueStatusCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new QueueStatusCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.QueueStatus instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.QueueStatus instance to insert.</param>
|
||||
public void Insert(int index, QueueStatus value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.QueueStatus.
|
||||
/// </summary>
|
||||
public class QueueStatusCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private QueueStatusCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private QueueStatus _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal QueueStatusCollectionEnumerator(QueueStatusCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.QueueStatus object in the enumerated QueueStatusCollection currently indexed by this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public QueueStatus Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,53 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class ResponseInfo : PersistableObject
|
||||
{
|
||||
public ResponseInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public ResponseInfo(string sentBy, string message)
|
||||
{
|
||||
TimeStamp = DateTime.UtcNow;
|
||||
SentBy = sentBy;
|
||||
Message = message;
|
||||
}
|
||||
|
||||
public DateTime TimeStamp{ get; set; }
|
||||
|
||||
public string SentBy{ get; set; }
|
||||
|
||||
public string Message{ get; set; }
|
||||
|
||||
public override void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
op.SetDateTime("t", TimeStamp);
|
||||
|
||||
op.SetString("s", SentBy);
|
||||
op.SetString("m", Message);
|
||||
}
|
||||
|
||||
public override void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
TimeStamp = ip.GetDateTime("t");
|
||||
|
||||
SentBy = ip.GetString("s");
|
||||
Message = ip.GetString("m");
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("rs", Construct);
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new ResponseInfo();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
//------------------------------------------------------------------------------
|
||||
// <autogenerated>
|
||||
// This code was generated by a tool.
|
||||
// Runtime Version: 1.1.4322.573
|
||||
//
|
||||
// Changes to this file may cause incorrect behavior and will be lost if
|
||||
// the code is regenerated.
|
||||
// </autogenerated>
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.ResponseInfo.
|
||||
/// </summary>
|
||||
public class ResponseInfoCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.ResponseInfo at a specific position in the ResponseInfoCollection.
|
||||
/// </summary>
|
||||
public ResponseInfo this[int index]
|
||||
{
|
||||
get => (ResponseInfo)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(string sentBy, string message)
|
||||
{
|
||||
return Add(new ResponseInfo(sentBy, message));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.ResponseInfo entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ResponseInfo instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(ResponseInfo value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.ResponseInfo instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ResponseInfo instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.ResponseInfo instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(ResponseInfo value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.ResponseInfo instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.ResponseInfo instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.ResponseInfo instance. If the object is not found, the
|
||||
/// return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(ResponseInfo value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.ResponseInfo instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.ResponseInfo instance to remove.</param>
|
||||
public void Remove(ResponseInfo value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.ResponseInfo instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.ResponseInfo's enumerator.</returns>
|
||||
public new ResponseInfoCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ResponseInfoCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.ResponseInfo instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.ResponseInfo instance to insert.</param>
|
||||
public void Insert(int index, ResponseInfo value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.ResponseInfo.
|
||||
/// </summary>
|
||||
public class ResponseInfoCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ResponseInfoCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private ResponseInfo _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ResponseInfoCollectionEnumerator(ResponseInfoCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.ResponseInfo object in the enumerated ResponseInfoCollection currently indexed by this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public ResponseInfo Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,399 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class StaffHistory : PersistableObject
|
||||
{
|
||||
public static readonly PersistableType ThisTypeID = new PersistableType("stfhst", Construct);
|
||||
public static readonly object RenderLock = new object();
|
||||
public static readonly object SaveLock = new object();
|
||||
|
||||
public StaffHistory()
|
||||
{
|
||||
Pages = new PageInfoCollection();
|
||||
QueueStats = new QueueStatusCollection();
|
||||
|
||||
UserInfo = new Dictionary<string, UserInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
StaffInfo = new Dictionary<string, StaffInfo>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public PageInfoCollection Pages{ get; set; }
|
||||
|
||||
public QueueStatusCollection QueueStats{ get; set; }
|
||||
|
||||
public Dictionary<string, UserInfo> UserInfo{ get; set; }
|
||||
|
||||
public Dictionary<string, StaffInfo> StaffInfo{ get; set; }
|
||||
|
||||
public void AddPage(PageInfo info)
|
||||
{
|
||||
lock (SaveLock)
|
||||
{
|
||||
Pages.Add(info);
|
||||
}
|
||||
|
||||
info.History = this;
|
||||
}
|
||||
|
||||
public StaffInfo GetStaffInfo(string account)
|
||||
{
|
||||
lock (RenderLock)
|
||||
{
|
||||
if (string.IsNullOrEmpty(account))
|
||||
return null;
|
||||
|
||||
if (!StaffInfo.TryGetValue(account, out StaffInfo info))
|
||||
StaffInfo[account] = info = new StaffInfo(account);
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
public UserInfo GetUserInfo(string account)
|
||||
{
|
||||
if (string.IsNullOrEmpty(account))
|
||||
return null;
|
||||
|
||||
if (!UserInfo.TryGetValue(account, out UserInfo info))
|
||||
UserInfo[account] = info = new UserInfo(account);
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public void Save()
|
||||
{
|
||||
lock (SaveLock)
|
||||
{
|
||||
string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml");
|
||||
PersistanceWriter pw = new XmlPersistanceWriter(path, "Staff");
|
||||
|
||||
pw.WriteDocument(this);
|
||||
|
||||
pw.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Load()
|
||||
{
|
||||
string path = Path.Combine(Core.BaseDirectory, "staffHistory.xml");
|
||||
|
||||
if (!File.Exists(path))
|
||||
return;
|
||||
|
||||
PersistanceReader pr = new XmlPersistanceReader(path, "Staff");
|
||||
|
||||
pr.ReadDocument(this);
|
||||
|
||||
pr.Close();
|
||||
}
|
||||
|
||||
public override void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
for (int i = 0; i < Pages.Count; ++i)
|
||||
Pages[i].Serialize(op);
|
||||
|
||||
for (int i = 0; i < QueueStats.Count; ++i)
|
||||
QueueStats[i].Serialize(op);
|
||||
}
|
||||
|
||||
public override void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
DateTime min = DateTime.UtcNow - TimeSpan.FromDays(8.0);
|
||||
|
||||
while (ip.HasChild)
|
||||
{
|
||||
PersistableObject obj = ip.GetChild();
|
||||
|
||||
if (obj is PageInfo pageInfo)
|
||||
{
|
||||
pageInfo.UpdateResolver();
|
||||
|
||||
if (pageInfo.TimeSent >= min || pageInfo.TimeResolved >= min)
|
||||
{
|
||||
Pages.Add(pageInfo);
|
||||
pageInfo.History = this;
|
||||
}
|
||||
else
|
||||
{
|
||||
pageInfo.Sender = null;
|
||||
pageInfo.Resolver = null;
|
||||
}
|
||||
}
|
||||
else if (obj is QueueStatus queueStatus)
|
||||
{
|
||||
if (queueStatus.TimeStamp >= min)
|
||||
QueueStats.Add(queueStatus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public StaffInfo[] GetStaff()
|
||||
{
|
||||
StaffInfo[] staff = new StaffInfo[StaffInfo.Count];
|
||||
int index = 0;
|
||||
|
||||
foreach (StaffInfo staffInfo in StaffInfo.Values)
|
||||
staff[index++] = staffInfo;
|
||||
|
||||
return staff;
|
||||
}
|
||||
|
||||
public void Render(ObjectCollection objects)
|
||||
{
|
||||
lock (RenderLock)
|
||||
{
|
||||
objects.Add(GraphQueueStatus());
|
||||
|
||||
StaffInfo[] staff = GetStaff();
|
||||
|
||||
BaseInfo.SortRange = TimeSpan.FromDays(7.0);
|
||||
Array.Sort(staff);
|
||||
|
||||
objects.Add(GraphHourlyPages(Pages, PageResolution.None, "New pages by hour", "graph_new_pages_hr"));
|
||||
objects.Add(GraphHourlyPages(Pages, PageResolution.Handled, "Handled pages by hour",
|
||||
"graph_handled_pages_hr"));
|
||||
objects.Add(GraphHourlyPages(Pages, PageResolution.Deleted, "Deleted pages by hour",
|
||||
"graph_deleted_pages_hr"));
|
||||
objects.Add(GraphHourlyPages(Pages, PageResolution.Canceled, "Canceled pages by hour",
|
||||
"graph_canceled_pages_hr"));
|
||||
objects.Add(GraphHourlyPages(Pages, PageResolution.Logged, "Logged-out pages by hour",
|
||||
"graph_logged_pages_hr"));
|
||||
|
||||
BaseInfo.SortRange = TimeSpan.FromDays(1.0);
|
||||
Array.Sort(staff);
|
||||
|
||||
objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day"));
|
||||
objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(1.0), "1 Day", "graph_daily_pages"));
|
||||
|
||||
BaseInfo.SortRange = TimeSpan.FromDays(7.0);
|
||||
Array.Sort(staff);
|
||||
|
||||
objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week"));
|
||||
objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(7.0), "1 Week", "graph_weekly_pages"));
|
||||
|
||||
BaseInfo.SortRange = TimeSpan.FromDays(30.0);
|
||||
Array.Sort(staff);
|
||||
|
||||
objects.Add(ReportTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month"));
|
||||
objects.AddRange(ChartTotalPages(staff, TimeSpan.FromDays(30.0), "1 Month", "graph_monthly_pages"));
|
||||
|
||||
for (int i = 0; i < staff.Length; ++i)
|
||||
objects.Add(GraphHourlyPages(staff[i]));
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetPageCount(StaffInfo staff, DateTime min, DateTime max)
|
||||
{
|
||||
return GetPageCount(staff.Pages, PageResolution.Handled, min, max);
|
||||
}
|
||||
|
||||
public static int GetPageCount(PageInfoCollection pages, PageResolution res, DateTime min, DateTime max)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
for (int i = 0; i < pages.Count; ++i)
|
||||
{
|
||||
if (res != PageResolution.None && pages[i].Resolution != res)
|
||||
continue;
|
||||
|
||||
DateTime ts = pages[i].TimeResolved;
|
||||
|
||||
if (ts >= min && ts < max)
|
||||
++count;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
private BarGraph GraphQueueStatus()
|
||||
{
|
||||
int[] totals = new int[24];
|
||||
int[] counts = new int[24];
|
||||
|
||||
DateTime max = DateTime.UtcNow;
|
||||
DateTime min = max - TimeSpan.FromDays(7.0);
|
||||
|
||||
for (int i = 0; i < QueueStats.Count; ++i)
|
||||
{
|
||||
DateTime ts = QueueStats[i].TimeStamp;
|
||||
|
||||
if (ts >= min && ts < max)
|
||||
{
|
||||
TimeSpan time = ts.TimeOfDay;
|
||||
|
||||
int hour = time.Hours;
|
||||
|
||||
totals[hour] += QueueStats[i].Count;
|
||||
counts[hour]++;
|
||||
}
|
||||
}
|
||||
|
||||
BarGraph barGraph = new BarGraph("Average pages in queue", "graph_pagequeue_avg", 10, "Time", "Pages",
|
||||
BarGraphRenderMode.Lines) { FontSize = 6 };
|
||||
|
||||
|
||||
for (int i = 7; i <= totals.Length + 7; ++i)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (counts[i % totals.Length] == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length];
|
||||
|
||||
int realHours = i % totals.Length;
|
||||
int hours;
|
||||
|
||||
if (realHours == 0)
|
||||
hours = 12;
|
||||
else if (realHours > 12)
|
||||
hours = realHours - 12;
|
||||
else
|
||||
hours = realHours;
|
||||
|
||||
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
||||
}
|
||||
|
||||
return barGraph;
|
||||
}
|
||||
|
||||
private BarGraph GraphHourlyPages(StaffInfo staff)
|
||||
{
|
||||
return GraphHourlyPages(staff.Pages, PageResolution.Handled, "Average pages handled by " + staff.Display,
|
||||
"graphs_" + staff.Account.ToLower() + "_avg");
|
||||
}
|
||||
|
||||
private BarGraph GraphHourlyPages(PageInfoCollection pages, PageResolution res, string title, string fname)
|
||||
{
|
||||
int[] totals = new int[24];
|
||||
int[] counts = new int[24];
|
||||
|
||||
DateTime[] dates = new DateTime[24];
|
||||
|
||||
DateTime max = DateTime.UtcNow;
|
||||
DateTime min = max - TimeSpan.FromDays(7.0);
|
||||
|
||||
bool sentStamp = res == PageResolution.None;
|
||||
|
||||
for (int i = 0; i < pages.Count; ++i)
|
||||
{
|
||||
if (res != PageResolution.None && pages[i].Resolution != res)
|
||||
continue;
|
||||
|
||||
DateTime ts = sentStamp ? pages[i].TimeSent : pages[i].TimeResolved;
|
||||
|
||||
if (ts >= min && ts < max)
|
||||
{
|
||||
DateTime date = ts.Date;
|
||||
TimeSpan time = ts.TimeOfDay;
|
||||
|
||||
int hour = time.Hours;
|
||||
|
||||
totals[hour]++;
|
||||
|
||||
if (dates[hour] != date)
|
||||
{
|
||||
counts[hour]++;
|
||||
dates[hour] = date;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BarGraph barGraph = new BarGraph(title, fname, 10, "Time", "Pages", BarGraphRenderMode.Lines) { FontSize = 6 };
|
||||
|
||||
|
||||
for (int i = 7; i <= totals.Length + 7; ++i)
|
||||
{
|
||||
int val;
|
||||
|
||||
if (counts[i % totals.Length] == 0)
|
||||
val = 0;
|
||||
else
|
||||
val = (totals[i % totals.Length] + counts[i % totals.Length] / 2) / counts[i % totals.Length];
|
||||
|
||||
int realHours = i % totals.Length;
|
||||
int hours;
|
||||
|
||||
if (realHours == 0)
|
||||
hours = 12;
|
||||
else if (realHours > 12)
|
||||
hours = realHours - 12;
|
||||
else
|
||||
hours = realHours;
|
||||
|
||||
barGraph.Items.Add(hours + (realHours >= 12 ? " PM" : " AM"), val);
|
||||
}
|
||||
|
||||
return barGraph;
|
||||
}
|
||||
|
||||
private Report ReportTotalPages(StaffInfo[] staff, TimeSpan ts, string title)
|
||||
{
|
||||
DateTime max = DateTime.UtcNow;
|
||||
DateTime min = max - ts;
|
||||
|
||||
Report report = new Report(title + " Staff Report", "400");
|
||||
|
||||
report.Columns.Add("65%", "left", "Staff Name");
|
||||
report.Columns.Add("35%", "center", "Page Count");
|
||||
|
||||
for (int i = 0; i < staff.Length; ++i)
|
||||
report.Items.Add(staff[i].Display, GetPageCount(staff[i], min, max));
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private PersistableObject[] ChartTotalPages(StaffInfo[] staff, TimeSpan ts, string title, string fname)
|
||||
{
|
||||
DateTime max = DateTime.UtcNow;
|
||||
DateTime min = max - ts;
|
||||
|
||||
PieChart staffChart = new PieChart(title + " Staff Chart", fname + "_staff", true);
|
||||
|
||||
int other = 0;
|
||||
|
||||
for (int i = 0; i < staff.Length; ++i)
|
||||
{
|
||||
int count = GetPageCount(staff[i], min, max);
|
||||
|
||||
if (i < 12 && count > 0)
|
||||
staffChart.Items.Add(staff[i].Display, count);
|
||||
else
|
||||
other += count;
|
||||
}
|
||||
|
||||
if (other > 0)
|
||||
staffChart.Items.Add("Other", other);
|
||||
|
||||
PieChart resChart = new PieChart(title + " Resolutions", fname + "_resol", true);
|
||||
|
||||
int countTotal = GetPageCount(Pages, PageResolution.None, min, max);
|
||||
int countHandled = GetPageCount(Pages, PageResolution.Handled, min, max);
|
||||
int countDeleted = GetPageCount(Pages, PageResolution.Deleted, min, max);
|
||||
int countCanceled = GetPageCount(Pages, PageResolution.Canceled, min, max);
|
||||
int countLogged = GetPageCount(Pages, PageResolution.Logged, min, max);
|
||||
int countUnres = countTotal - (countHandled + countDeleted + countCanceled + countLogged);
|
||||
|
||||
resChart.Items.Add("Handled", countHandled);
|
||||
resChart.Items.Add("Deleted", countDeleted);
|
||||
resChart.Items.Add("Canceled", countCanceled);
|
||||
resChart.Items.Add("Logged Out", countLogged);
|
||||
resChart.Items.Add("Unresolved", countUnres);
|
||||
|
||||
return new PersistableObject[] { staffChart, resChart };
|
||||
}
|
||||
|
||||
#region Type Identification
|
||||
|
||||
private static PersistableObject Construct()
|
||||
{
|
||||
return new StaffHistory();
|
||||
}
|
||||
|
||||
public override PersistableType TypeID => ThisTypeID;
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
namespace Server.Engines.Reports
|
||||
{
|
||||
public abstract class PersistableObject
|
||||
{
|
||||
public abstract PersistableType TypeID{ get; }
|
||||
|
||||
public virtual void SerializeAttributes(PersistanceWriter op)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void SerializeChildren(PersistanceWriter op)
|
||||
{
|
||||
}
|
||||
|
||||
public void Serialize(PersistanceWriter op)
|
||||
{
|
||||
op.BeginObject(TypeID);
|
||||
SerializeAttributes(op);
|
||||
op.BeginChildren();
|
||||
SerializeChildren(op);
|
||||
op.FinishChildren();
|
||||
op.FinishObject();
|
||||
}
|
||||
|
||||
public virtual void DeserializeAttributes(PersistanceReader ip)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void DeserializeChildren(PersistanceReader ip)
|
||||
{
|
||||
}
|
||||
|
||||
public void Deserialize(PersistanceReader ip)
|
||||
{
|
||||
DeserializeAttributes(ip);
|
||||
|
||||
if (ip.BeginChildren())
|
||||
{
|
||||
DeserializeChildren(ip);
|
||||
ip.FinishChildren();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,178 +0,0 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
/// <summary>
|
||||
/// Strongly typed collection of Server.Engines.Reports.PersistableObject.
|
||||
/// </summary>
|
||||
public class ObjectCollection : CollectionBase
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the value of the Server.Engines.Reports.PersistableObject at a specific position in the ObjectCollection.
|
||||
/// </summary>
|
||||
public PersistableObject this[int index]
|
||||
{
|
||||
get => (PersistableObject)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Append a Server.Engines.Reports.PersistableObject entry to this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PersistableObject instance.</param>
|
||||
/// <returns>The position into which the new element was inserted.</returns>
|
||||
public int Add(PersistableObject value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
public void AddRange(PersistableObject[] col)
|
||||
{
|
||||
InnerList.AddRange(col);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether a specified Server.Engines.Reports.PersistableObject instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PersistableObject instance to search for.</param>
|
||||
/// <returns>True if the Server.Engines.Reports.PersistableObject instance is in the collection; otherwise false.</returns>
|
||||
public bool Contains(PersistableObject value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Retrieve the index a specified Server.Engines.Reports.PersistableObject instance is in this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">Server.Engines.Reports.PersistableObject instance to find.</param>
|
||||
/// <returns>
|
||||
/// The zero-based index of the specified Server.Engines.Reports.PersistableObject instance. If the object is not
|
||||
/// found, the return value is -1.
|
||||
/// </returns>
|
||||
public int IndexOf(PersistableObject value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes a specified Server.Engines.Reports.PersistableObject instance from this collection.
|
||||
/// </summary>
|
||||
/// <param name="value">The Server.Engines.Reports.PersistableObject instance to remove.</param>
|
||||
public void Remove(PersistableObject value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Returns an enumerator that can iterate through the Server.Engines.Reports.PersistableObject instance.
|
||||
/// </summary>
|
||||
/// <returns>An Server.Engines.Reports.PersistableObject's enumerator.</returns>
|
||||
public new ObjectCollectionEnumerator GetEnumerator()
|
||||
{
|
||||
return new ObjectCollectionEnumerator(this);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Insert a Server.Engines.Reports.PersistableObject instance into this collection at a specified index.
|
||||
/// </summary>
|
||||
/// <param name="index">Zero-based index.</param>
|
||||
/// <param name="value">The Server.Engines.Reports.PersistableObject instance to insert.</param>
|
||||
public void Insert(int index, PersistableObject value)
|
||||
{
|
||||
List.Insert(index, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Strongly typed enumerator of Server.Engines.Reports.PersistableObject.
|
||||
/// </summary>
|
||||
public class ObjectCollectionEnumerator : IEnumerator
|
||||
{
|
||||
/// <summary>
|
||||
/// Collection to enumerate.
|
||||
/// </summary>
|
||||
private ObjectCollection _collection;
|
||||
|
||||
/// <summary>
|
||||
/// Current element pointed to.
|
||||
/// </summary>
|
||||
private PersistableObject _currentElement;
|
||||
|
||||
/// <summary>
|
||||
/// Current index
|
||||
/// </summary>
|
||||
private int _index;
|
||||
|
||||
/// <summary>
|
||||
/// Default constructor for enumerator.
|
||||
/// </summary>
|
||||
/// <param name="collection">Instance of the collection to enumerate.</param>
|
||||
internal ObjectCollectionEnumerator(ObjectCollection collection)
|
||||
{
|
||||
_index = -1;
|
||||
_collection = collection;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the Server.Engines.Reports.PersistableObject object in the enumerated ObjectCollection currently indexed by this
|
||||
/// instance.
|
||||
/// </summary>
|
||||
public PersistableObject Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current element in the collection.
|
||||
/// </summary>
|
||||
object IEnumerator.Current
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_index == -1
|
||||
|| _index >= _collection.Count)
|
||||
throw new IndexOutOfRangeException("Enumerator not started.");
|
||||
|
||||
return _currentElement;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reset the cursor, so it points to the beginning of the enumerator.
|
||||
/// </summary>
|
||||
public void Reset()
|
||||
{
|
||||
_index = -1;
|
||||
_currentElement = null;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Advances the enumerator to the next queue of the enumeration, if one is currently available.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// true, if the enumerator was successfully advanced to the next queue; false, if the enumerator has reached the end
|
||||
/// of the enumeration.
|
||||
/// </returns>
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (_index
|
||||
< _collection.Count - 1)
|
||||
{
|
||||
_index = _index + 1;
|
||||
_currentElement = _collection[_index];
|
||||
return true;
|
||||
}
|
||||
|
||||
_index = _collection.Count;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,57 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public delegate PersistableObject ConstructCallback();
|
||||
|
||||
public sealed class PersistableTypeRegistry
|
||||
{
|
||||
private static Dictionary<string, PersistableType> m_Table;
|
||||
|
||||
static PersistableTypeRegistry()
|
||||
{
|
||||
m_Table = new Dictionary<string, PersistableType>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
Register(Report.ThisTypeID);
|
||||
Register(BarGraph.ThisTypeID);
|
||||
Register(PieChart.ThisTypeID);
|
||||
Register(Snapshot.ThisTypeID);
|
||||
Register(ItemValue.ThisTypeID);
|
||||
Register(ChartItem.ThisTypeID);
|
||||
Register(ReportItem.ThisTypeID);
|
||||
Register(ReportColumn.ThisTypeID);
|
||||
Register(SnapshotHistory.ThisTypeID);
|
||||
|
||||
Register(PageInfo.ThisTypeID);
|
||||
Register(QueueStatus.ThisTypeID);
|
||||
Register(StaffHistory.ThisTypeID);
|
||||
Register(ResponseInfo.ThisTypeID);
|
||||
}
|
||||
|
||||
public static PersistableType Find(string name)
|
||||
{
|
||||
m_Table.TryGetValue(name, out PersistableType value);
|
||||
return value;
|
||||
}
|
||||
|
||||
public static void Register(PersistableType type)
|
||||
{
|
||||
if (type != null)
|
||||
m_Table[type.Name] = type;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class PersistableType
|
||||
{
|
||||
public PersistableType(string name, ConstructCallback constructor)
|
||||
{
|
||||
Name = name;
|
||||
Constructor = constructor;
|
||||
}
|
||||
|
||||
public string Name{ get; }
|
||||
|
||||
public ConstructCallback Constructor{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,111 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public abstract class PersistanceReader
|
||||
{
|
||||
public abstract bool HasChild{ get; }
|
||||
public abstract int GetInt32(string key);
|
||||
public abstract bool GetBoolean(string key);
|
||||
public abstract string GetString(string key);
|
||||
public abstract DateTime GetDateTime(string key);
|
||||
|
||||
public abstract bool BeginChildren();
|
||||
public abstract void FinishChildren();
|
||||
public abstract PersistableObject GetChild();
|
||||
|
||||
public abstract void ReadDocument(PersistableObject root);
|
||||
public abstract void Close();
|
||||
}
|
||||
|
||||
public class XmlPersistanceReader : PersistanceReader
|
||||
{
|
||||
private bool m_HasChild;
|
||||
private StreamReader m_Reader;
|
||||
private string m_Title;
|
||||
|
||||
private bool m_WasEmptyElement;
|
||||
private XmlTextReader m_Xml;
|
||||
|
||||
public XmlPersistanceReader(string filePath, string title)
|
||||
{
|
||||
m_Reader = new StreamReader(filePath);
|
||||
m_Xml = new XmlTextReader(m_Reader);
|
||||
m_Xml.WhitespaceHandling = WhitespaceHandling.None;
|
||||
m_Title = title;
|
||||
}
|
||||
|
||||
public override bool HasChild => m_HasChild;
|
||||
|
||||
public override int GetInt32(string key)
|
||||
{
|
||||
return XmlConvert.ToInt32(m_Xml.GetAttribute(key) ?? "");
|
||||
}
|
||||
|
||||
public override bool GetBoolean(string key)
|
||||
{
|
||||
return XmlConvert.ToBoolean(m_Xml.GetAttribute(key) ?? "");
|
||||
}
|
||||
|
||||
public override string GetString(string key)
|
||||
{
|
||||
return m_Xml.GetAttribute(key);
|
||||
}
|
||||
|
||||
public override DateTime GetDateTime(string key)
|
||||
{
|
||||
string val = m_Xml.GetAttribute(key);
|
||||
|
||||
if (val == null)
|
||||
return DateTime.MinValue;
|
||||
|
||||
return XmlConvert.ToDateTime(val, XmlDateTimeSerializationMode.Utc);
|
||||
}
|
||||
|
||||
public override bool BeginChildren()
|
||||
{
|
||||
m_HasChild = !m_WasEmptyElement;
|
||||
|
||||
m_Xml.Read();
|
||||
|
||||
return m_HasChild;
|
||||
}
|
||||
|
||||
public override void FinishChildren()
|
||||
{
|
||||
m_Xml.Read();
|
||||
}
|
||||
|
||||
public override PersistableObject GetChild()
|
||||
{
|
||||
PersistableType type = PersistableTypeRegistry.Find(m_Xml.Name);
|
||||
PersistableObject obj = type.Constructor();
|
||||
|
||||
m_WasEmptyElement = m_Xml.IsEmptyElement;
|
||||
|
||||
obj.Deserialize(this);
|
||||
|
||||
m_HasChild = m_Xml.NodeType == XmlNodeType.Element;
|
||||
|
||||
return obj;
|
||||
}
|
||||
|
||||
public override void ReadDocument(PersistableObject root)
|
||||
{
|
||||
Console.Write("Reports: {0}: Loading...", m_Title);
|
||||
m_Xml.Read();
|
||||
m_Xml.Read();
|
||||
m_HasChild = !m_Xml.IsEmptyElement;
|
||||
root.Deserialize(this);
|
||||
Console.WriteLine("done");
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
m_Xml.Close();
|
||||
m_Reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,125 +0,0 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public abstract class PersistanceWriter
|
||||
{
|
||||
public abstract void SetInt32(string key, int value);
|
||||
public abstract void SetBoolean(string key, bool value);
|
||||
public abstract void SetString(string key, string value);
|
||||
public abstract void SetDateTime(string key, DateTime value);
|
||||
|
||||
public abstract void BeginObject(PersistableType typeID);
|
||||
public abstract void BeginChildren();
|
||||
public abstract void FinishChildren();
|
||||
public abstract void FinishObject();
|
||||
|
||||
public abstract void WriteDocument(PersistableObject root);
|
||||
public abstract void Close();
|
||||
}
|
||||
|
||||
public sealed class XmlPersistanceWriter : PersistanceWriter
|
||||
{
|
||||
private string m_RealFilePath;
|
||||
private string m_TempFilePath;
|
||||
private string m_Title;
|
||||
|
||||
private StreamWriter m_Writer;
|
||||
private XmlTextWriter m_Xml;
|
||||
|
||||
public XmlPersistanceWriter(string filePath, string title)
|
||||
{
|
||||
m_RealFilePath = filePath;
|
||||
m_TempFilePath = Path.ChangeExtension(filePath, ".tmp");
|
||||
|
||||
m_Writer = new StreamWriter(m_TempFilePath);
|
||||
m_Xml = new XmlTextWriter(m_Writer);
|
||||
|
||||
m_Title = title;
|
||||
}
|
||||
|
||||
public override void SetInt32(string key, int value)
|
||||
{
|
||||
m_Xml.WriteAttributeString(key, XmlConvert.ToString(value));
|
||||
}
|
||||
|
||||
public override void SetBoolean(string key, bool value)
|
||||
{
|
||||
m_Xml.WriteAttributeString(key, XmlConvert.ToString(value));
|
||||
}
|
||||
|
||||
public override void SetString(string key, string value)
|
||||
{
|
||||
if (value != null)
|
||||
m_Xml.WriteAttributeString(key, value);
|
||||
}
|
||||
|
||||
public override void SetDateTime(string key, DateTime value)
|
||||
{
|
||||
if (value != DateTime.MinValue)
|
||||
m_Xml.WriteAttributeString(key, XmlConvert.ToString(value, XmlDateTimeSerializationMode.Utc));
|
||||
}
|
||||
|
||||
public override void BeginObject(PersistableType typeID)
|
||||
{
|
||||
m_Xml.WriteStartElement(typeID.Name);
|
||||
}
|
||||
|
||||
public override void BeginChildren()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FinishChildren()
|
||||
{
|
||||
}
|
||||
|
||||
public override void FinishObject()
|
||||
{
|
||||
m_Xml.WriteEndElement();
|
||||
}
|
||||
|
||||
public override void WriteDocument(PersistableObject root)
|
||||
{
|
||||
Console.WriteLine("Reports: {0}: Save started", m_Title);
|
||||
|
||||
m_Xml.Formatting = Formatting.Indented;
|
||||
m_Xml.IndentChar = '\t';
|
||||
m_Xml.Indentation = 1;
|
||||
|
||||
m_Xml.WriteStartDocument(true);
|
||||
|
||||
root.Serialize(this);
|
||||
|
||||
Console.WriteLine("Reports: {0}: Save complete", m_Title);
|
||||
}
|
||||
|
||||
public override void Close()
|
||||
{
|
||||
m_Xml.Close();
|
||||
m_Writer.Close();
|
||||
|
||||
try
|
||||
{
|
||||
string renamed;
|
||||
|
||||
if (File.Exists(m_RealFilePath))
|
||||
{
|
||||
renamed = Path.ChangeExtension(m_RealFilePath, ".rem");
|
||||
File.Move(m_RealFilePath, renamed);
|
||||
File.Move(m_TempFilePath, m_RealFilePath);
|
||||
File.Delete(renamed);
|
||||
}
|
||||
else
|
||||
{
|
||||
File.Move(m_TempFilePath, m_RealFilePath);
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,934 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Drawing.Imaging;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
// Modified from MS sample
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// BarGraph Class
|
||||
//
|
||||
// This class uses GDI+ to render Bar Chart.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public class BarRegion
|
||||
{
|
||||
public string m_Name;
|
||||
public int m_RangeFrom, m_RangeTo;
|
||||
|
||||
public BarRegion(int rangeFrom, int rangeTo, string name)
|
||||
{
|
||||
m_RangeFrom = rangeFrom;
|
||||
m_RangeTo = rangeTo;
|
||||
m_Name = name;
|
||||
}
|
||||
}
|
||||
|
||||
public class BarGraphRenderer : ChartRenderer
|
||||
{
|
||||
private const float _graphLegendSpacer = 15F;
|
||||
private const float _labelFontSize = 7f;
|
||||
private const int _legendFontSize = 9;
|
||||
private const float _legendRectangleSize = 10F;
|
||||
private const float _spacer = 5F;
|
||||
|
||||
// Overall related members
|
||||
private Color _backColor;
|
||||
|
||||
// Graph related members
|
||||
private float _barWidth;
|
||||
private float _bottomBuffer; // Space from bottom to x axis
|
||||
private Color _fontColor;
|
||||
private float _graphHeight;
|
||||
private float _graphWidth;
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method draws all the bars for the graph.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public int _interval;
|
||||
|
||||
// Legend related members
|
||||
private float _legendWidth;
|
||||
private string _longestLabel = string.Empty; // Used to calculate legend width
|
||||
private string _longestTickValue = string.Empty; // Used to calculate max value width
|
||||
private float _maxLabelWidth;
|
||||
private float _maxTickValueWidth; // Used to calculate left offset of bar graph
|
||||
private float _maxValue; // = final tick value * tick count
|
||||
|
||||
public BarRegion[] _regions;
|
||||
private float _scaleFactor; // = _maxValue / _graphHeight
|
||||
private float _spaceBtwBars; // For now same as _barWidth
|
||||
private float _topBuffer; // Space from top to the top of y axis
|
||||
private float _totalHeight;
|
||||
private float _totalWidth;
|
||||
private float _xOrigin; // x position where graph starts drawing
|
||||
|
||||
private string _xTitle, _yTitle;
|
||||
private float _yOrigin; // y position where graph starts drawing
|
||||
private float _yTickValue; // Value for each tick = _maxValue/_yTickCount
|
||||
|
||||
public BarGraphRenderer()
|
||||
{
|
||||
AssignDefaultSettings();
|
||||
}
|
||||
|
||||
public BarGraphRenderer(Color bgColor)
|
||||
{
|
||||
AssignDefaultSettings();
|
||||
BackgroundColor = bgColor;
|
||||
}
|
||||
|
||||
public string FontFamily{ get; set; }
|
||||
|
||||
public BarGraphRenderMode RenderMode{ get; set; }
|
||||
|
||||
public Color BackgroundColor
|
||||
{
|
||||
set => _backColor = value;
|
||||
}
|
||||
|
||||
public int BottomBuffer
|
||||
{
|
||||
set => _bottomBuffer = Convert.ToSingle(value);
|
||||
}
|
||||
|
||||
public Color FontColor
|
||||
{
|
||||
set => _fontColor = value;
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => Convert.ToInt32(_totalHeight);
|
||||
set => _totalHeight = Convert.ToSingle(value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => Convert.ToInt32(_totalWidth);
|
||||
set => _totalWidth = Convert.ToSingle(value);
|
||||
}
|
||||
|
||||
public bool ShowLegend{ get; set; }
|
||||
|
||||
public bool ShowData{ get; set; }
|
||||
|
||||
public int TopBuffer
|
||||
{
|
||||
set => _topBuffer = Convert.ToSingle(value);
|
||||
}
|
||||
|
||||
public string VerticalLabel{ get; set; }
|
||||
|
||||
public int VerticalTickCount{ get; set; }
|
||||
|
||||
public void SetTitles(string xTitle, string yTitle)
|
||||
{
|
||||
_xTitle = xTitle;
|
||||
_yTitle = yTitle;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method collects all data points and calculate all the necessary dimensions
|
||||
// to draw the bar graph. It is the method called before invoking the Draw() method.
|
||||
// labels is the x values.
|
||||
// values is the y values.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public void CollectDataPoints(string[] labels, string[] values)
|
||||
{
|
||||
if (labels.Length == values.Length)
|
||||
{
|
||||
for (int i = 0; i < labels.Length; i++)
|
||||
{
|
||||
float temp = Convert.ToSingle(values[i]);
|
||||
string shortLbl = MakeShortLabel(labels[i]);
|
||||
|
||||
// For now put 0.0 for start position and sweep size
|
||||
DataPoints.Add(new DataItem(shortLbl, labels[i], temp, 0.0f, 0.0f, GetColor(i)));
|
||||
|
||||
// Find max value from data; this is only temporary _maxValue
|
||||
if (_maxValue < temp) _maxValue = temp;
|
||||
|
||||
// Find the longest description
|
||||
if (ShowLegend)
|
||||
{
|
||||
string currentLbl = labels[i] + " (" + shortLbl + ")";
|
||||
float currentWidth = CalculateImgFontWidth(currentLbl, _legendFontSize, FontFamily);
|
||||
if (_maxLabelWidth < currentWidth)
|
||||
{
|
||||
_longestLabel = currentLbl;
|
||||
_maxLabelWidth = currentWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CalculateTickAndMax();
|
||||
CalculateGraphDimension();
|
||||
CalculateBarWidth(DataPoints.Count, _graphWidth);
|
||||
CalculateSweepValues();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new Exception("X data count is different from Y data count");
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// Same as above; called when user doesn't care about the x values
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public void CollectDataPoints(string[] values)
|
||||
{
|
||||
string[] labels = values;
|
||||
CollectDataPoints(labels, values);
|
||||
}
|
||||
|
||||
public void DrawRegions(Graphics gfx)
|
||||
{
|
||||
if (_regions == null)
|
||||
return;
|
||||
|
||||
using (StringFormat textFormat = new StringFormat())
|
||||
{
|
||||
textFormat.Alignment = StringAlignment.Center;
|
||||
textFormat.LineAlignment = StringAlignment.Center;
|
||||
|
||||
using (Font font = new Font(FontFamily, _labelFontSize))
|
||||
{
|
||||
using (Brush textBrush = new SolidBrush(_fontColor))
|
||||
{
|
||||
using (Pen solidPen = new Pen(_fontColor))
|
||||
{
|
||||
using (Pen lightPen = new Pen(Color.FromArgb(128, _fontColor)))
|
||||
{
|
||||
float labelWidth = _barWidth + _spaceBtwBars;
|
||||
|
||||
for (int i = 0; i < _regions.Length; ++i)
|
||||
{
|
||||
BarRegion reg = _regions[i];
|
||||
|
||||
RectangleF rc = new RectangleF(_xOrigin + reg.m_RangeFrom * labelWidth, _yOrigin,
|
||||
(reg.m_RangeTo - reg.m_RangeFrom + 1) * labelWidth, _graphHeight);
|
||||
|
||||
if (rc.X + rc.Width > _xOrigin + _graphWidth)
|
||||
rc.Width = _xOrigin + _graphWidth - rc.X;
|
||||
|
||||
using (SolidBrush brsh = new SolidBrush(Color.FromArgb(48, GetColor(i))))
|
||||
{
|
||||
gfx.FillRectangle(brsh, rc);
|
||||
}
|
||||
|
||||
rc.Offset((rc.Width - 200.0f) * 0.5f, -16.0f);
|
||||
rc.Width = 200.0f;
|
||||
rc.Height = 20.0f;
|
||||
|
||||
gfx.DrawString(reg.m_Name, font, textBrush, rc, textFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method returns a bar graph bitmap to the calling function. It is called after
|
||||
// all dimensions and data points are calculated.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public override Bitmap Draw()
|
||||
{
|
||||
int height = Convert.ToInt32(_totalHeight);
|
||||
int width = Convert.ToInt32(_totalWidth);
|
||||
|
||||
Bitmap bmp = new Bitmap(width, height);
|
||||
|
||||
using (Graphics graph = Graphics.FromImage(bmp))
|
||||
{
|
||||
graph.CompositingQuality = CompositingQuality.HighQuality;
|
||||
graph.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
|
||||
using (SolidBrush brsh = new SolidBrush(_backColor))
|
||||
{
|
||||
graph.FillRectangle(brsh, -1, -1, bmp.Width + 1, bmp.Height + 1);
|
||||
}
|
||||
|
||||
DrawRegions(graph);
|
||||
DrawVerticalLabelArea(graph);
|
||||
DrawXLabelBack(graph);
|
||||
DrawBars(graph);
|
||||
DrawXLabelArea(graph);
|
||||
|
||||
if (ShowLegend)
|
||||
DrawLegend(graph);
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
private void DrawBars(Graphics graph)
|
||||
{
|
||||
SolidBrush brsFont = null;
|
||||
Font valFont = null;
|
||||
StringFormat sfFormat = null;
|
||||
|
||||
try
|
||||
{
|
||||
brsFont = new SolidBrush(_fontColor);
|
||||
valFont = new Font(FontFamily, _labelFontSize);
|
||||
sfFormat = new StringFormat();
|
||||
sfFormat.Alignment = StringAlignment.Center;
|
||||
int i = 0;
|
||||
|
||||
PointF[] linePoints = null;
|
||||
|
||||
if (RenderMode == BarGraphRenderMode.Lines)
|
||||
linePoints = new PointF[DataPoints.Count];
|
||||
|
||||
int pointIndex = 0;
|
||||
|
||||
// Draw bars and the value above each bar
|
||||
using (Pen pen = new Pen(_fontColor, 0.15f))
|
||||
{
|
||||
using (SolidBrush whiteBrsh = new SolidBrush(Color.FromArgb(128, Color.White)))
|
||||
{
|
||||
foreach (DataItem item in DataPoints)
|
||||
using (SolidBrush barBrush = new SolidBrush(item.ItemColor))
|
||||
{
|
||||
float itemY = _yOrigin + _graphHeight - item.SweepSize;
|
||||
|
||||
if (RenderMode == BarGraphRenderMode.Lines)
|
||||
{
|
||||
linePoints[pointIndex++] = new PointF(_xOrigin + item.StartPos + _barWidth / 2, itemY);
|
||||
}
|
||||
else if (RenderMode == BarGraphRenderMode.Bars)
|
||||
{
|
||||
float ox = _xOrigin + item.StartPos;
|
||||
float oy = itemY;
|
||||
float ow = _barWidth;
|
||||
float oh = item.SweepSize;
|
||||
float of = 9.5f;
|
||||
|
||||
PointF[] pts =
|
||||
{
|
||||
new PointF(ox, oy),
|
||||
new PointF(ox + ow, oy),
|
||||
new PointF(ox + of, oy + of),
|
||||
new PointF(ox + of + ow, oy + of),
|
||||
new PointF(ox, oy + oh),
|
||||
new PointF(ox + of, oy + of + oh),
|
||||
new PointF(ox + of + ow, oy + of + oh)
|
||||
};
|
||||
|
||||
graph.FillPolygon(barBrush, new[] { pts[2], pts[3], pts[6], pts[5] });
|
||||
|
||||
using (SolidBrush ltBrsh = new SolidBrush(ControlPaint.Light(item.ItemColor, 0.1f)))
|
||||
{
|
||||
graph.FillPolygon(ltBrsh, new[] { pts[0], pts[2], pts[5], pts[4] });
|
||||
}
|
||||
|
||||
using (SolidBrush drkBrush = new SolidBrush(ControlPaint.Dark(item.ItemColor, 0.05f)))
|
||||
{
|
||||
graph.FillPolygon(drkBrush, new[] { pts[0], pts[1], pts[3], pts[2] });
|
||||
}
|
||||
|
||||
graph.DrawLine(pen, pts[0], pts[1]);
|
||||
graph.DrawLine(pen, pts[0], pts[2]);
|
||||
graph.DrawLine(pen, pts[1], pts[3]);
|
||||
graph.DrawLine(pen, pts[2], pts[3]);
|
||||
graph.DrawLine(pen, pts[2], pts[5]);
|
||||
graph.DrawLine(pen, pts[0], pts[4]);
|
||||
graph.DrawLine(pen, pts[4], pts[5]);
|
||||
graph.DrawLine(pen, pts[5], pts[6]);
|
||||
graph.DrawLine(pen, pts[3], pts[6]);
|
||||
|
||||
// Draw data value
|
||||
if (ShowData && i % _interval == 0)
|
||||
{
|
||||
float sectionWidth = _barWidth + _spaceBtwBars;
|
||||
float startX =
|
||||
_xOrigin + i * sectionWidth +
|
||||
sectionWidth / 2; // This draws the value on center of the bar
|
||||
float startY =
|
||||
itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels
|
||||
RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY,
|
||||
sectionWidth * _interval, valFont.Height);
|
||||
SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size,
|
||||
sfFormat);
|
||||
//using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 180, 255, 255, 255 ) ) )
|
||||
// graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) );
|
||||
|
||||
//graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal, sfFormat);
|
||||
|
||||
for (int box = -1; box <= 1; ++box)
|
||||
for (int boy = -1; boy <= 1; ++boy)
|
||||
{
|
||||
if (box == 0 && boy == 0)
|
||||
continue;
|
||||
|
||||
RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width,
|
||||
recVal.Height);
|
||||
graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco,
|
||||
sfFormat);
|
||||
}
|
||||
|
||||
graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal,
|
||||
sfFormat);
|
||||
}
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
if (RenderMode == BarGraphRenderMode.Lines)
|
||||
{
|
||||
if (linePoints.Length >= 2)
|
||||
using (Pen linePen = new Pen(Color.FromArgb(220, Color.Red), 2.5f))
|
||||
{
|
||||
graph.DrawCurve(linePen, linePoints, 0.5f);
|
||||
}
|
||||
|
||||
using (Pen linePen = new Pen(Color.FromArgb(40, _fontColor), 0.8f))
|
||||
{
|
||||
for (int j = 0; j < linePoints.Length; ++j)
|
||||
{
|
||||
graph.DrawLine(linePen, linePoints[j],
|
||||
new PointF(linePoints[j].X, _yOrigin + _graphHeight));
|
||||
|
||||
DataItem item = DataPoints[j];
|
||||
float itemY = _yOrigin + _graphHeight - item.SweepSize;
|
||||
|
||||
// Draw data value
|
||||
if (ShowData && j % _interval == 0)
|
||||
{
|
||||
graph.FillEllipse(brsFont,
|
||||
new RectangleF(linePoints[j].X - 2.0f, linePoints[j].Y - 2.0f, 4.0f, 4.0f));
|
||||
|
||||
float sectionWidth = _barWidth + _spaceBtwBars;
|
||||
float startX =
|
||||
_xOrigin + j * sectionWidth +
|
||||
sectionWidth / 2; // This draws the value on center of the bar
|
||||
float startY =
|
||||
itemY - 2f - valFont.Height; // Positioned on top of each bar by 2 pixels
|
||||
RectangleF recVal = new RectangleF(startX - sectionWidth * _interval / 2, startY,
|
||||
sectionWidth * _interval, valFont.Height);
|
||||
SizeF sz = graph.MeasureString(item.Value.ToString("#,###.##"), valFont, recVal.Size,
|
||||
sfFormat);
|
||||
//using ( SolidBrush brsh = new SolidBrush( Color.FromArgb( 48, 255, 255, 255 ) ) )
|
||||
// graph.FillRectangle( brsh, new RectangleF(recVal.X+((recVal.Width-sz.Width)/2),recVal.Y+((recVal.Height-sz.Height)/2),sz.Width+4,sz.Height) );
|
||||
|
||||
for (int box = -1; box <= 1; ++box)
|
||||
for (int boy = -1; boy <= 1; ++boy)
|
||||
{
|
||||
if (box == 0 && boy == 0)
|
||||
continue;
|
||||
|
||||
RectangleF rco = new RectangleF(recVal.X + box, recVal.Y + boy, recVal.Width,
|
||||
recVal.Height);
|
||||
graph.DrawString(item.Value.ToString("#,###.##"), valFont, whiteBrsh, rco,
|
||||
sfFormat);
|
||||
}
|
||||
|
||||
graph.DrawString(item.Value.ToString("#,###.##"), valFont, brsFont, recVal,
|
||||
sfFormat);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
brsFont?.Dispose();
|
||||
valFont?.Dispose();
|
||||
sfFormat?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method draws the y label, tick marks, tick values, and the y axis.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void DrawVerticalLabelArea(Graphics graph)
|
||||
{
|
||||
Font lblFont = null;
|
||||
SolidBrush brs = null;
|
||||
StringFormat lblFormat = null;
|
||||
Pen pen = null;
|
||||
StringFormat sfVLabel = null;
|
||||
|
||||
float fo = _yTitle == null ? 0.0f : 20.0f;
|
||||
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(_fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(_fontColor);
|
||||
|
||||
if (_yTitle != null)
|
||||
{
|
||||
sfVLabel = new StringFormat();
|
||||
sfVLabel.Alignment = StringAlignment.Center;
|
||||
sfVLabel.LineAlignment = StringAlignment.Center;
|
||||
sfVLabel.FormatFlags = StringFormatFlags.DirectionVertical;
|
||||
|
||||
lblFont = new Font(FontFamily, _labelFontSize + 4.0f);
|
||||
graph.DrawString(_yTitle, lblFont, brs, new RectangleF(0.0f, _yOrigin, 20.0f, _graphHeight), sfVLabel);
|
||||
lblFont.Dispose();
|
||||
}
|
||||
|
||||
sfVLabel = new StringFormat();
|
||||
lblFormat.Alignment = StringAlignment.Far;
|
||||
lblFormat.FormatFlags |= StringFormatFlags.NoClip;
|
||||
|
||||
// Draw vertical label at the top of y-axis and place it in the middle top of y-axis
|
||||
lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold);
|
||||
RectangleF recVLabel =
|
||||
new RectangleF(0, _yOrigin - 2 * _spacer - lblFont.Height, _xOrigin * 2, lblFont.Height);
|
||||
sfVLabel.Alignment = StringAlignment.Center;
|
||||
sfVLabel.FormatFlags |= StringFormatFlags.NoClip;
|
||||
//graph.DrawRectangle(Pens.Black,Rectangle.Truncate(recVLabel));
|
||||
graph.DrawString(VerticalLabel, lblFont, brs, recVLabel, sfVLabel);
|
||||
lblFont.Dispose();
|
||||
|
||||
lblFont = new Font(FontFamily, _labelFontSize);
|
||||
// Draw all tick values and tick marks
|
||||
using (Pen smallPen = new Pen(Color.FromArgb(96, _fontColor), 0.8f))
|
||||
{
|
||||
for (int i = 0; i < VerticalTickCount; i++)
|
||||
{
|
||||
float currentY = _topBuffer + i * _yTickValue / _scaleFactor; // Position for tick mark
|
||||
float labelY = currentY - lblFont.Height / 2.0f; // Place label in the middle of tick
|
||||
RectangleF lblRec = new RectangleF(_spacer + fo - 6, labelY, _maxTickValueWidth, lblFont.Height);
|
||||
|
||||
float currentTick = _maxValue - i * _yTickValue; // Calculate tick value from top to bottom
|
||||
graph.DrawString(currentTick.ToString("#,###.##"), lblFont, brs, lblRec,
|
||||
lblFormat); // Draw tick value
|
||||
graph.DrawLine(pen, _xOrigin, currentY, _xOrigin - 4.0f, currentY); // Draw tick mark
|
||||
|
||||
graph.DrawLine(smallPen, _xOrigin, currentY, _xOrigin + _graphWidth, currentY);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw y axis
|
||||
graph.DrawLine(pen, _xOrigin, _yOrigin, _xOrigin, _yOrigin + _graphHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lblFont?.Dispose();
|
||||
brs?.Dispose();
|
||||
lblFormat?.Dispose();
|
||||
pen?.Dispose();
|
||||
sfVLabel?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method draws x axis and all x labels
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void DrawXLabelBack(Graphics graph)
|
||||
{
|
||||
Font lblFont = null;
|
||||
SolidBrush brs = null;
|
||||
StringFormat lblFormat = null;
|
||||
Pen pen = null;
|
||||
|
||||
try
|
||||
{
|
||||
lblFont = new Font(FontFamily, _labelFontSize);
|
||||
brs = new SolidBrush(_fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(_fontColor);
|
||||
|
||||
lblFormat.Alignment = StringAlignment.Center;
|
||||
|
||||
// Draw x axis
|
||||
graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + _graphWidth, _yOrigin + _graphHeight);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lblFont?.Dispose();
|
||||
brs?.Dispose();
|
||||
lblFormat?.Dispose();
|
||||
pen?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawXLabelArea(Graphics graph)
|
||||
{
|
||||
Font lblFont = null;
|
||||
SolidBrush brs = null;
|
||||
StringFormat lblFormat = null;
|
||||
Pen pen = null;
|
||||
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(_fontColor);
|
||||
pen = new Pen(_fontColor);
|
||||
|
||||
if (_xTitle != null)
|
||||
{
|
||||
lblFormat = new StringFormat();
|
||||
lblFormat.Alignment = StringAlignment.Center;
|
||||
lblFormat.LineAlignment = StringAlignment.Center;
|
||||
// sfVLabel.FormatFlags=StringFormatFlags.DirectionVertical;
|
||||
|
||||
lblFont = new Font(FontFamily, _labelFontSize + 2.0f, FontStyle.Bold);
|
||||
graph.DrawString(_xTitle, lblFont, brs,
|
||||
new RectangleF(_xOrigin,
|
||||
_yOrigin + _graphHeight + 14.0f + (RenderMode == BarGraphRenderMode.Bars ? 10.0f : 0.0f) +
|
||||
(DataPoints.Count / _interval > 24 ? 16.0f : 0.0f), _graphWidth, 20.0f), lblFormat);
|
||||
}
|
||||
|
||||
lblFont = new Font(FontFamily, _labelFontSize);
|
||||
lblFormat = new StringFormat();
|
||||
lblFormat.Alignment = StringAlignment.Center;
|
||||
lblFormat.FormatFlags |= StringFormatFlags.NoClip;
|
||||
lblFormat.Trimming = StringTrimming.None;
|
||||
//lblFormat.FormatFlags |= StringFormatFlags.NoWrap;
|
||||
|
||||
float of = 0.0f;
|
||||
|
||||
if (RenderMode == BarGraphRenderMode.Bars)
|
||||
{
|
||||
of = 10.0f;
|
||||
|
||||
// Draw x axis
|
||||
graph.DrawLine(pen, _xOrigin + of, _yOrigin + _graphHeight + of, _xOrigin + _graphWidth + of,
|
||||
_yOrigin + _graphHeight + of);
|
||||
|
||||
graph.DrawLine(pen, _xOrigin, _yOrigin + _graphHeight, _xOrigin + of, _yOrigin + _graphHeight + of);
|
||||
graph.DrawLine(pen, _xOrigin + _graphWidth, _yOrigin + _graphHeight, _xOrigin + of + _graphWidth,
|
||||
_yOrigin + _graphHeight + of);
|
||||
}
|
||||
|
||||
float currentX;
|
||||
float currentY = _yOrigin + _graphHeight + 2.0f; // All x labels are drawn 2 pixels below x-axis
|
||||
float labelWidth = _barWidth + _spaceBtwBars; // Fits exactly below the bar
|
||||
int i = 0;
|
||||
|
||||
// Draw x labels
|
||||
foreach (DataItem item in DataPoints)
|
||||
{
|
||||
if (i % _interval == 0)
|
||||
{
|
||||
currentX = _xOrigin + i * labelWidth + of + labelWidth / 2;
|
||||
RectangleF recLbl = new RectangleF(currentX - labelWidth * _interval / 2, currentY + of,
|
||||
labelWidth * _interval, lblFont.Height * 2);
|
||||
string lblString = ShowLegend ? item.Label : item.Description; // Decide what to show: short or long
|
||||
|
||||
graph.DrawString(lblString, lblFont, brs, recLbl, lblFormat);
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
finally
|
||||
{
|
||||
lblFont?.Dispose();
|
||||
brs?.Dispose();
|
||||
lblFormat?.Dispose();
|
||||
pen?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method determines where to place the legend box.
|
||||
// It draws the legend border, legend description, and legend color code.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void DrawLegend(Graphics graph)
|
||||
{
|
||||
Font lblFont = null;
|
||||
SolidBrush brs = null;
|
||||
StringFormat lblFormat = null;
|
||||
Pen pen = null;
|
||||
|
||||
try
|
||||
{
|
||||
lblFont = new Font(FontFamily, _legendFontSize);
|
||||
brs = new SolidBrush(_fontColor);
|
||||
lblFormat = new StringFormat();
|
||||
pen = new Pen(_fontColor);
|
||||
lblFormat.Alignment = StringAlignment.Near;
|
||||
|
||||
// Calculate Legend drawing start point
|
||||
float startX = _xOrigin + _graphWidth + _graphLegendSpacer;
|
||||
float startY = _yOrigin;
|
||||
|
||||
float xColorCode = startX + _spacer;
|
||||
float xLegendText = xColorCode + _legendRectangleSize + _spacer;
|
||||
float legendHeight = 0.0f;
|
||||
for (int i = 0; i < DataPoints.Count; i++)
|
||||
{
|
||||
DataItem point = DataPoints[i];
|
||||
string text = point.Description + " (" + point.Label + ")";
|
||||
float currentY = startY + _spacer + i * (lblFont.Height + _spacer);
|
||||
legendHeight += lblFont.Height + _spacer;
|
||||
|
||||
// Draw legend description
|
||||
graph.DrawString(text, lblFont, brs, xLegendText, currentY, lblFormat);
|
||||
|
||||
// Draw color code
|
||||
using (SolidBrush brsh = new SolidBrush(DataPoints[i].ItemColor))
|
||||
{
|
||||
graph.FillRectangle(brsh, xColorCode, currentY + 3f, _legendRectangleSize, _legendRectangleSize);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw legend border
|
||||
graph.DrawRectangle(pen, startX, startY, _legendWidth, legendHeight + _spacer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
lblFont?.Dispose();
|
||||
brs?.Dispose();
|
||||
lblFormat?.Dispose();
|
||||
pen?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates all measurement aspects of the bar graph from the given data points
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void CalculateGraphDimension()
|
||||
{
|
||||
FindLongestTickValue();
|
||||
|
||||
// Need to add another character for spacing; this is not used for drawing, just for calculation
|
||||
_longestTickValue += "0";
|
||||
//_maxTickValueWidth = CalculateImgFontWidth(_longestTickValue, _labelFontSize, FontFamily);
|
||||
_maxTickValueWidth = 0.0f;
|
||||
|
||||
|
||||
float currentTick;
|
||||
string tickString;
|
||||
for (int i = 0; i < VerticalTickCount; i++)
|
||||
{
|
||||
currentTick = _maxValue - i * _yTickValue;
|
||||
tickString = currentTick.ToString("#,###.##");
|
||||
|
||||
float measured = CalculateImgFontWidth(tickString, _labelFontSize, FontFamily);
|
||||
|
||||
if (measured > _maxTickValueWidth)
|
||||
_maxTickValueWidth = measured;
|
||||
}
|
||||
|
||||
float leftOffset = _spacer + _maxTickValueWidth + (_yTitle == null ? 0.0f : 20.0f);
|
||||
float rtOffset = 0.0f;
|
||||
|
||||
if (ShowLegend)
|
||||
{
|
||||
_legendWidth = _spacer + _legendRectangleSize + _spacer + _maxLabelWidth + _spacer;
|
||||
rtOffset = _graphLegendSpacer + _legendWidth + _spacer;
|
||||
}
|
||||
else
|
||||
{
|
||||
rtOffset = _spacer; // Make graph in the middle
|
||||
}
|
||||
|
||||
if (RenderMode == BarGraphRenderMode.Bars)
|
||||
rtOffset += 10.0f;
|
||||
|
||||
rtOffset += 10.0f;
|
||||
|
||||
_graphHeight =
|
||||
_totalHeight - _topBuffer - _bottomBuffer -
|
||||
(_xTitle == null ? 0.0f : 20.0f); // Buffer spaces are used to print labels
|
||||
_graphWidth = _totalWidth - leftOffset - rtOffset;
|
||||
_xOrigin = leftOffset;
|
||||
_yOrigin = _topBuffer;
|
||||
|
||||
// Once the correct _maxValue is determined, then calculate _scaleFactor
|
||||
_scaleFactor = _maxValue / _graphHeight;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method determines the longest tick value from the given data points.
|
||||
// The result is needed to calculate the correct graph dimension.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void FindLongestTickValue()
|
||||
{
|
||||
float currentTick;
|
||||
string tickString;
|
||||
for (int i = 0; i < VerticalTickCount; i++)
|
||||
{
|
||||
currentTick = _maxValue - i * _yTickValue;
|
||||
tickString = currentTick.ToString("#,###.##");
|
||||
if (_longestTickValue.Length < tickString.Length)
|
||||
_longestTickValue = tickString;
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the image width in pixel for a given text
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private float CalculateImgFontWidth(string text, float size, string family)
|
||||
{
|
||||
Bitmap bmp = null;
|
||||
Graphics graph = null;
|
||||
Font font = null;
|
||||
|
||||
try
|
||||
{
|
||||
font = new Font(family, size);
|
||||
|
||||
// Calculate the size of the string.
|
||||
bmp = new Bitmap(1, 1, PixelFormat.Format32bppArgb);
|
||||
graph = Graphics.FromImage(bmp);
|
||||
SizeF oSize = graph.MeasureString(text, font);
|
||||
oSize.Width = 4 + (float)Math.Ceiling(oSize.Width);
|
||||
|
||||
return oSize.Width;
|
||||
}
|
||||
finally
|
||||
{
|
||||
graph?.Dispose();
|
||||
bmp?.Dispose();
|
||||
font?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method creates abbreviation from long description; used for making legend
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private string MakeShortLabel(string text)
|
||||
{
|
||||
string label = text;
|
||||
if (text.Length > 2)
|
||||
{
|
||||
int midPostition = Convert.ToInt32(Math.Floor(text.Length / 2.0));
|
||||
label = text.Substring(0, 1) + text.Substring(midPostition, 1) + text.Substring(text.Length - 1, 1);
|
||||
}
|
||||
|
||||
return label;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the max value and each tick mark value for the bar graph.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void CalculateTickAndMax()
|
||||
{
|
||||
float tempMax = 0.0f;
|
||||
|
||||
// Give graph some head room first about 10% of current max
|
||||
_maxValue *= 1.1f;
|
||||
|
||||
if (_maxValue != 0.0f)
|
||||
{
|
||||
// Find a rounded value nearest to the current max value
|
||||
// Calculate this max first to give enough space to draw value on each bar
|
||||
double exp = Convert.ToDouble(Math.Floor(Math.Log10(_maxValue)));
|
||||
tempMax = Convert.ToSingle(Math.Ceiling(_maxValue / Math.Pow(10, exp)) * Math.Pow(10, exp));
|
||||
}
|
||||
else
|
||||
{
|
||||
tempMax = 1.0f;
|
||||
}
|
||||
|
||||
// Once max value is calculated, tick value can be determined; tick value should be a whole number
|
||||
_yTickValue = tempMax / VerticalTickCount;
|
||||
double expTick = Convert.ToDouble(Math.Floor(Math.Log10(_yTickValue)));
|
||||
_yTickValue = Convert.ToSingle(Math.Ceiling(_yTickValue / Math.Pow(10, expTick)) * Math.Pow(10, expTick));
|
||||
|
||||
// Re-calculate the max value with the new tick value
|
||||
_maxValue = _yTickValue * VerticalTickCount;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the height for each bar in the graph
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void CalculateSweepValues()
|
||||
{
|
||||
// Called when all values and scale factor are known
|
||||
// All values calculated here are relative from (_xOrigin, _yOrigin)
|
||||
int i = 0;
|
||||
foreach (DataItem item in DataPoints)
|
||||
{
|
||||
// This implementation does not support negative value
|
||||
if (item.Value >= 0) item.SweepSize = item.Value / _scaleFactor;
|
||||
|
||||
// (_spaceBtwBars/2) makes half white space for the first bar
|
||||
item.StartPos = _spaceBtwBars / 2 + i * (_barWidth + _spaceBtwBars);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the width for each bar in the graph
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void CalculateBarWidth(int dataCount, float barGraphWidth)
|
||||
{
|
||||
// White space between each bar is the same as bar width itself
|
||||
_barWidth = barGraphWidth / (dataCount * 2); // Each bar has 1 white space
|
||||
//_barWidth =/* (float)Math.Floor(*/_barWidth/*)*/;
|
||||
_spaceBtwBars = _barWidth;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method assigns default value to the bar graph properties and is only
|
||||
// called from BarGraph constructors
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void AssignDefaultSettings()
|
||||
{
|
||||
// default values
|
||||
_totalWidth = 680f;
|
||||
_totalHeight = 450f;
|
||||
FontFamily = "Verdana";
|
||||
_backColor = Color.White;
|
||||
_fontColor = Color.Black;
|
||||
_topBuffer = 30f;
|
||||
_bottomBuffer = 30f;
|
||||
VerticalTickCount = 2;
|
||||
ShowLegend = false;
|
||||
ShowData = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
//*********************************************************************
|
||||
//
|
||||
// Chart Class
|
||||
//
|
||||
// Base class implementation for BarChart and PieChart
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public abstract class ChartRenderer
|
||||
{
|
||||
private const int _colorLimit = 9;
|
||||
|
||||
private Color[] _color =
|
||||
{
|
||||
Color.Firebrick,
|
||||
Color.SkyBlue,
|
||||
Color.MediumSeaGreen,
|
||||
Color.MediumOrchid,
|
||||
Color.Chocolate,
|
||||
Color.SlateBlue,
|
||||
Color.LightPink,
|
||||
Color.LightGreen,
|
||||
Color.Khaki
|
||||
};
|
||||
|
||||
public ChartItemsCollection DataPoints{ get; set; } = new ChartItemsCollection();
|
||||
|
||||
// Represent collection of all data points for the chart
|
||||
|
||||
// The implementation of this method is provided by derived classes
|
||||
public abstract Bitmap Draw();
|
||||
|
||||
public void SetColor(int index, Color NewColor)
|
||||
{
|
||||
if (index < _colorLimit)
|
||||
_color[index] = NewColor;
|
||||
else
|
||||
throw new Exception("Color Limit is " + _colorLimit);
|
||||
}
|
||||
|
||||
public Color GetColor(int index)
|
||||
{
|
||||
//return _color[index%_colorLimit];
|
||||
|
||||
if (index < _colorLimit) return _color[index];
|
||||
|
||||
return _color[(index + 2) % _colorLimit];
|
||||
//throw new Exception("Color Limit is " + _colorLimit);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,63 +0,0 @@
|
|||
using System.Collections;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class DataItem
|
||||
{
|
||||
private DataItem()
|
||||
{
|
||||
}
|
||||
|
||||
public DataItem(string label, string desc, float data, float start, float sweep, Color clr)
|
||||
{
|
||||
Label = label;
|
||||
Description = desc;
|
||||
Value = data;
|
||||
StartPos = start;
|
||||
SweepSize = sweep;
|
||||
ItemColor = clr;
|
||||
}
|
||||
|
||||
public string Label{ get; set; }
|
||||
|
||||
public string Description{ get; set; }
|
||||
|
||||
public float Value{ get; set; }
|
||||
|
||||
public Color ItemColor{ get; set; }
|
||||
|
||||
public float StartPos{ get; set; }
|
||||
|
||||
public float SweepSize{ get; set; }
|
||||
}
|
||||
|
||||
public class ChartItemsCollection : CollectionBase
|
||||
{
|
||||
public DataItem this[int index]
|
||||
{
|
||||
get => (DataItem)List[index];
|
||||
set => List[index] = value;
|
||||
}
|
||||
|
||||
public int Add(DataItem value)
|
||||
{
|
||||
return List.Add(value);
|
||||
}
|
||||
|
||||
public int IndexOf(DataItem value)
|
||||
{
|
||||
return List.IndexOf(value);
|
||||
}
|
||||
|
||||
public bool Contains(DataItem value)
|
||||
{
|
||||
return List.Contains(value);
|
||||
}
|
||||
|
||||
public void Remove(DataItem value)
|
||||
{
|
||||
List.Remove(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,546 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Imaging;
|
||||
using System.IO;
|
||||
using System.Web.UI;
|
||||
using HtmlTag = System.Web.UI.HtmlTextWriterTag;
|
||||
using HtmlAttr = System.Web.UI.HtmlTextWriterAttribute;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class HtmlRenderer
|
||||
{
|
||||
private const string ShardTitle = "Shard";
|
||||
|
||||
private static readonly string FtpHost = null;
|
||||
|
||||
private static readonly string FtpUsername = null;
|
||||
private static readonly string FtpPassword = null;
|
||||
|
||||
private static readonly string FtpStatsDirectory = null;
|
||||
private static readonly string FtpStaffDirectory = null;
|
||||
private ObjectCollection m_Objects;
|
||||
private string m_OutputDirectory;
|
||||
|
||||
private DateTime m_TimeStamp;
|
||||
private string m_Title;
|
||||
private string m_Type;
|
||||
|
||||
private HtmlRenderer(string outputDirectory)
|
||||
{
|
||||
m_Type = outputDirectory;
|
||||
m_Title = m_Type == "staff" ? "Staff" : "Stats";
|
||||
m_OutputDirectory = Path.Combine(Core.BaseDirectory, "output");
|
||||
|
||||
if (!Directory.Exists(m_OutputDirectory))
|
||||
Directory.CreateDirectory(m_OutputDirectory);
|
||||
|
||||
m_OutputDirectory = Path.Combine(m_OutputDirectory, outputDirectory);
|
||||
|
||||
if (!Directory.Exists(m_OutputDirectory))
|
||||
Directory.CreateDirectory(m_OutputDirectory);
|
||||
}
|
||||
|
||||
public HtmlRenderer(string outputDirectory, Snapshot ss, SnapshotHistory history) : this(outputDirectory)
|
||||
{
|
||||
m_TimeStamp = ss.TimeStamp;
|
||||
|
||||
m_Objects = new ObjectCollection();
|
||||
|
||||
for (int i = 0; i < ss.Children.Count; ++i)
|
||||
m_Objects.Add(ss.Children[i]);
|
||||
|
||||
m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Clients", 1, 100, 6));
|
||||
m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Items", 24, 9, 1));
|
||||
m_Objects.Add(BarGraph.OverTime(history, "General Stats", "Players", 24, 9, 1));
|
||||
m_Objects.Add(BarGraph.OverTime(history, "General Stats", "NPCs", 24, 9, 1));
|
||||
m_Objects.Add(BarGraph.DailyAverage(history, "General Stats", "Clients"));
|
||||
m_Objects.Add(BarGraph.Growth(history, "General Stats", "Clients"));
|
||||
}
|
||||
|
||||
public HtmlRenderer(string outputDirectory, StaffHistory history) : this(outputDirectory)
|
||||
{
|
||||
m_TimeStamp = DateTime.UtcNow;
|
||||
|
||||
m_Objects = new ObjectCollection();
|
||||
|
||||
history.Render(m_Objects);
|
||||
}
|
||||
|
||||
public void Render()
|
||||
{
|
||||
Console.WriteLine("Reports: {0}: Render started", m_Title);
|
||||
|
||||
RenderFull();
|
||||
|
||||
for (int i = 0; i < m_Objects.Count; ++i)
|
||||
RenderSingle(m_Objects[i]);
|
||||
|
||||
Console.WriteLine("Reports: {0}: Render complete", m_Title);
|
||||
}
|
||||
|
||||
public void Upload()
|
||||
{
|
||||
if (FtpHost == null)
|
||||
return;
|
||||
|
||||
Console.WriteLine("Reports: {0}: Upload started", m_Title);
|
||||
|
||||
string filePath = Path.Combine(m_OutputDirectory, "upload.ftp");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
op.WriteLine("open \"{0}\"", FtpHost);
|
||||
op.WriteLine(FtpUsername);
|
||||
op.WriteLine(FtpPassword);
|
||||
op.WriteLine("cd \"{0}\"", m_Type == "staff" ? FtpStaffDirectory : FtpStatsDirectory);
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.html"));
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.css"));
|
||||
op.WriteLine("binary");
|
||||
op.WriteLine("mput \"{0}\"", Path.Combine(m_OutputDirectory, "*.png"));
|
||||
op.WriteLine("disconnect");
|
||||
op.Write("quit");
|
||||
}
|
||||
|
||||
ProcessStartInfo psi = new ProcessStartInfo();
|
||||
|
||||
psi.FileName = "ftp";
|
||||
psi.Arguments = $"-i -s:\"{filePath}\"";
|
||||
|
||||
psi.CreateNoWindow = true;
|
||||
psi.WindowStyle = ProcessWindowStyle.Hidden;
|
||||
//psi.UseShellExecute = true;
|
||||
|
||||
try
|
||||
{
|
||||
Process p = Process.Start(psi);
|
||||
|
||||
p?.WaitForExit();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Console.WriteLine("Reports: {0}: Upload complete", m_Title);
|
||||
|
||||
try
|
||||
{
|
||||
File.Delete(filePath);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderFull()
|
||||
{
|
||||
string filePath = Path.Combine(m_OutputDirectory, "reports.html");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
||||
{
|
||||
RenderFull(html);
|
||||
}
|
||||
}
|
||||
|
||||
string cssPath = Path.Combine(m_OutputDirectory, "styles.css");
|
||||
|
||||
if (File.Exists(cssPath))
|
||||
return;
|
||||
|
||||
using (StreamWriter css = new StreamWriter(cssPath))
|
||||
{
|
||||
css.WriteLine("body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }");
|
||||
css.WriteLine("a { color: #28435E; }");
|
||||
css.WriteLine("a:hover { color: #4878A9; }");
|
||||
css.WriteLine("td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }");
|
||||
css.WriteLine("td.lentry { background-color: #D7D7EB; width: 10%; }");
|
||||
css.WriteLine("td.rentry { background-color: #FFFFFF; width: 90%; }");
|
||||
css.WriteLine("td.entry { background-color: #FFFFFF; }");
|
||||
css.WriteLine("td { font-size: 11px; }");
|
||||
css.Write(".tbl-border { background-color: #46465A; }");
|
||||
}
|
||||
}
|
||||
|
||||
public void RenderFull(HtmlTextWriter html)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Html);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Head);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Title);
|
||||
html.Write("{0} Statistics", ShardTitle);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.AddAttribute("rel", "stylesheet");
|
||||
html.AddAttribute(HtmlAttr.Type, "text/css");
|
||||
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
||||
html.RenderBeginTag(HtmlTag.Link);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Body);
|
||||
|
||||
for (int i = 0; i < m_Objects.Count; ++i)
|
||||
{
|
||||
RenderDirect(m_Objects[i], html);
|
||||
html.Write("<br><br>");
|
||||
}
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Center);
|
||||
TimeZone tz = TimeZone.CurrentTimeZone;
|
||||
|
||||
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
public static string SafeFileName(string name)
|
||||
{
|
||||
return name.ToLower().Replace(' ', '_');
|
||||
}
|
||||
|
||||
public void RenderSingle(PersistableObject obj)
|
||||
{
|
||||
string filePath = Path.Combine(m_OutputDirectory, SafeFileName(FindNameFrom(obj)) + ".html");
|
||||
|
||||
using (StreamWriter op = new StreamWriter(filePath))
|
||||
{
|
||||
using (HtmlTextWriter html = new HtmlTextWriter(op, "\t"))
|
||||
{
|
||||
RenderSingle(obj, html);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private string FindNameFrom(PersistableObject obj)
|
||||
{
|
||||
if (obj is Report report)
|
||||
return report.Name;
|
||||
if (obj is Chart chart)
|
||||
return chart.Name;
|
||||
|
||||
return "Invalid";
|
||||
}
|
||||
|
||||
public void RenderSingle(PersistableObject obj, HtmlTextWriter html)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Html);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Head);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Title);
|
||||
html.Write("{0} Statistics - {1}", ShardTitle, FindNameFrom(obj));
|
||||
html.RenderEndTag();
|
||||
|
||||
html.AddAttribute("rel", "stylesheet");
|
||||
html.AddAttribute(HtmlAttr.Type, "text/css");
|
||||
html.AddAttribute(HtmlAttr.Href, "styles.css");
|
||||
html.RenderBeginTag(HtmlTag.Link);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Body);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Center);
|
||||
|
||||
RenderDirect(obj, html);
|
||||
|
||||
html.Write("<br>");
|
||||
|
||||
TimeZone tz = TimeZone.CurrentTimeZone;
|
||||
|
||||
html.Write("Snapshot taken at {0:d} {0:t}. All times are {1}.", m_TimeStamp, tz.StandardName);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
public void RenderDirect(PersistableObject obj, HtmlTextWriter html)
|
||||
{
|
||||
if (obj is Report report)
|
||||
RenderReport(report, html);
|
||||
else if (obj is BarGraph graph)
|
||||
RenderBarGraph(graph, html);
|
||||
else if (obj is PieChart chart)
|
||||
RenderPieChart(chart, html);
|
||||
}
|
||||
|
||||
private void RenderPieChart(PieChart chart, HtmlTextWriter html)
|
||||
{
|
||||
PieChartRenderer pieChart = new PieChartRenderer(Color.White);
|
||||
|
||||
pieChart.ShowPercents = chart.ShowPercents;
|
||||
|
||||
string[] labels = new string[chart.Items.Count];
|
||||
string[] values = new string[chart.Items.Count];
|
||||
|
||||
for (int i = 0; i < chart.Items.Count; ++i)
|
||||
{
|
||||
ChartItem item = chart.Items[i];
|
||||
|
||||
labels[i] = item.Name;
|
||||
values[i] = item.Value.ToString();
|
||||
}
|
||||
|
||||
pieChart.CollectDataPoints(labels, values);
|
||||
|
||||
Bitmap bmp = pieChart.Draw();
|
||||
|
||||
string fileName = chart.FileName + ".png";
|
||||
bmp.Save(Path.Combine(m_OutputDirectory, fileName), ImageFormat.Png);
|
||||
|
||||
html.Write("<!-- ");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Href, "#");
|
||||
html.AddAttribute(HtmlAttr.Onclick,
|
||||
$"javascript:window.open('{SafeFileName(FindNameFrom(chart))}.html','ChildWindow','width={bmp.Width + 30},height={bmp.Height + 80},resizable=no,status=no,toolbar=no')");
|
||||
html.RenderBeginTag(HtmlTag.A);
|
||||
html.Write(chart.Name);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.Write(" -->");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(chart.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
||||
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
||||
html.AddAttribute(HtmlAttr.Src, fileName);
|
||||
html.RenderBeginTag(HtmlTag.Img);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bmp.Dispose();
|
||||
}
|
||||
|
||||
private void RenderBarGraph(BarGraph graph, HtmlTextWriter html)
|
||||
{
|
||||
BarGraphRenderer barGraph = new BarGraphRenderer(Color.White);
|
||||
|
||||
barGraph.RenderMode = graph.RenderMode;
|
||||
|
||||
barGraph._regions = graph.Regions;
|
||||
barGraph.SetTitles(graph.xTitle, null);
|
||||
|
||||
if (graph.yTitle != null)
|
||||
barGraph.VerticalLabel = graph.yTitle;
|
||||
|
||||
barGraph.FontColor = Color.Black;
|
||||
barGraph.ShowData = graph.Interval == 1;
|
||||
barGraph.VerticalTickCount = graph.Ticks;
|
||||
|
||||
string[] labels = new string[graph.Items.Count];
|
||||
string[] values = new string[graph.Items.Count];
|
||||
|
||||
for (int i = 0; i < graph.Items.Count; ++i)
|
||||
{
|
||||
ChartItem item = graph.Items[i];
|
||||
|
||||
labels[i] = item.Name;
|
||||
values[i] = item.Value.ToString();
|
||||
}
|
||||
|
||||
barGraph._interval = graph.Interval;
|
||||
barGraph.CollectDataPoints(labels, values);
|
||||
|
||||
Bitmap bmp = barGraph.Draw();
|
||||
|
||||
string fileName = graph.FileName + ".png";
|
||||
bmp.Save(Path.Combine(m_OutputDirectory, fileName), ImageFormat.Png);
|
||||
|
||||
html.Write("<!-- ");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Href, "#");
|
||||
html.AddAttribute(HtmlAttr.Onclick,
|
||||
$"javascript:window.open('{SafeFileName(FindNameFrom(graph))}.html','ChildWindow','width={bmp.Width + 30},height={bmp.Height + 80},resizable=no,status=no,toolbar=no')");
|
||||
html.RenderBeginTag(HtmlTag.A);
|
||||
html.Write(graph.Name);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.Write(" -->");
|
||||
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(graph.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, bmp.Width.ToString());
|
||||
html.AddAttribute(HtmlAttr.Height, bmp.Height.ToString());
|
||||
html.AddAttribute(HtmlAttr.Src, fileName);
|
||||
html.RenderBeginTag(HtmlTag.Img);
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bmp.Dispose();
|
||||
}
|
||||
|
||||
private void RenderReport(Report report, HtmlTextWriter html)
|
||||
{
|
||||
html.AddAttribute(HtmlAttr.Width, report.Width);
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "0");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "0");
|
||||
html.AddAttribute(HtmlAttr.Border, "0");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Class, "tbl-border");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Cellpadding, "4");
|
||||
html.AddAttribute(HtmlAttr.Cellspacing, "1");
|
||||
html.RenderBeginTag(HtmlTag.Table);
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
html.AddAttribute(HtmlAttr.Colspan, "10");
|
||||
html.AddAttribute(HtmlAttr.Width, "100%");
|
||||
html.AddAttribute(HtmlAttr.Align, "center");
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
html.Write(report.Name);
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
|
||||
bool isNamed = false;
|
||||
|
||||
for (int i = 0; i < report.Columns.Count && !isNamed; ++i)
|
||||
isNamed = report.Columns[i].Name != null;
|
||||
|
||||
if (isNamed)
|
||||
{
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
for (int i = 0; i < report.Columns.Count; ++i)
|
||||
{
|
||||
ReportColumn column = report.Columns[i];
|
||||
|
||||
html.AddAttribute(HtmlAttr.Class, "header");
|
||||
html.AddAttribute(HtmlAttr.Width, column.Width);
|
||||
html.AddAttribute(HtmlAttr.Align, column.Align);
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
html.Write(column.Name);
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
for (int i = 0; i < report.Items.Count; ++i)
|
||||
{
|
||||
ReportItem item = report.Items[i];
|
||||
|
||||
html.RenderBeginTag(HtmlTag.Tr);
|
||||
|
||||
for (int j = 0; j < item.Values.Count; ++j)
|
||||
{
|
||||
if (!isNamed && j == 0)
|
||||
html.AddAttribute(HtmlAttr.Width, report.Columns[j].Width);
|
||||
|
||||
html.AddAttribute(HtmlAttr.Align, report.Columns[j].Align);
|
||||
html.AddAttribute(HtmlAttr.Class, "entry");
|
||||
html.RenderBeginTag(HtmlTag.Td);
|
||||
|
||||
if (item.Values[j].Format == null)
|
||||
html.Write(item.Values[j].Value);
|
||||
else
|
||||
html.Write(int.Parse(item.Values[j].Value).ToString(item.Values[j].Format));
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
}
|
||||
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
html.RenderEndTag();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,249 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
// Modified from MS sample
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// PieChart Class
|
||||
//
|
||||
// This class uses GDI+ to render Pie Chart.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public class PieChartRenderer : ChartRenderer
|
||||
{
|
||||
private const int _bufferSpace = 125;
|
||||
private Color _backgroundColor;
|
||||
private Color _borderColor;
|
||||
private List<DataItem> _chartItems;
|
||||
private int _legendFontHeight;
|
||||
private float _legendFontSize;
|
||||
private string _legendFontStyle;
|
||||
private int _legendHeight;
|
||||
private int _legendWidth;
|
||||
private int _perimeter;
|
||||
private float _total;
|
||||
|
||||
public PieChartRenderer() : this(Color.White)
|
||||
{
|
||||
}
|
||||
|
||||
public PieChartRenderer(Color bgColor)
|
||||
{
|
||||
_chartItems = new List<DataItem>();
|
||||
_perimeter = 250;
|
||||
_backgroundColor = bgColor;
|
||||
_borderColor = Color.FromArgb(63, 63, 63);
|
||||
_legendFontSize = 8;
|
||||
_legendFontStyle = "Verdana";
|
||||
}
|
||||
|
||||
public bool ShowPercents{ get; set; }
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method collects all data points and calculate all the necessary dimensions
|
||||
// to draw the chart. It is the first method called before invoking the Draw() method.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public void CollectDataPoints(string[] xValues, string[] yValues)
|
||||
{
|
||||
_total = 0.0f;
|
||||
|
||||
for (int i = 0; i < xValues.Length; i++)
|
||||
{
|
||||
float ftemp = Convert.ToSingle(yValues[i]);
|
||||
_chartItems.Add(new DataItem(xValues[i], xValues.ToString(), ftemp, 0, 0, Color.AliceBlue));
|
||||
_total += ftemp;
|
||||
}
|
||||
|
||||
float nextStartPos = 0.0f;
|
||||
int counter = 0;
|
||||
foreach (DataItem item in _chartItems)
|
||||
{
|
||||
item.StartPos = nextStartPos;
|
||||
item.SweepSize = item.Value / _total * 360;
|
||||
nextStartPos = item.StartPos + item.SweepSize;
|
||||
item.ItemColor = GetColor(counter++);
|
||||
}
|
||||
|
||||
CalculateLegendWidthHeight();
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method returns a bitmap to the calling function. This is the method
|
||||
// that actually draws the pie chart and the legend with it.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
public override Bitmap Draw()
|
||||
{
|
||||
int perimeter = _perimeter;
|
||||
Rectangle pieRect = new Rectangle(0, 0, perimeter, perimeter - 1);
|
||||
Bitmap bmp = new Bitmap(perimeter + _legendWidth, perimeter);
|
||||
Font fnt = null;
|
||||
Pen pen = null;
|
||||
Graphics grp = null;
|
||||
StringFormat sf = null, sfp = null;
|
||||
|
||||
try
|
||||
{
|
||||
grp = Graphics.FromImage(bmp);
|
||||
grp.CompositingQuality = CompositingQuality.HighQuality;
|
||||
grp.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
sf = new StringFormat();
|
||||
|
||||
//Paint Back ground
|
||||
using (SolidBrush brsh = new SolidBrush(_backgroundColor))
|
||||
{
|
||||
grp.FillRectangle(brsh, -1, -1, perimeter + _legendWidth + 1, perimeter + 1);
|
||||
}
|
||||
|
||||
//Align text to the right
|
||||
sf.Alignment = StringAlignment.Far;
|
||||
|
||||
//Draw all wedges and legends
|
||||
for (int i = 0; i < _chartItems.Count; i++)
|
||||
{
|
||||
DataItem item = _chartItems[i];
|
||||
SolidBrush brs = null;
|
||||
try
|
||||
{
|
||||
brs = new SolidBrush(item.ItemColor);
|
||||
grp.FillPie(brs, pieRect, item.StartPos, item.SweepSize);
|
||||
|
||||
//grp.DrawPie(new Pen(_borderColor,1.2f),pieRect,item.StartPos,item.SweepSize);
|
||||
|
||||
if (fnt == null)
|
||||
fnt = new Font(_legendFontStyle, _legendFontSize);
|
||||
|
||||
if (ShowPercents && item.SweepSize > 10)
|
||||
{
|
||||
if (sfp == null)
|
||||
{
|
||||
sfp = new StringFormat();
|
||||
sfp.Alignment = StringAlignment.Center;
|
||||
sfp.LineAlignment = StringAlignment.Center;
|
||||
}
|
||||
|
||||
float perc = item.SweepSize * 100.0f / 360.0f;
|
||||
string percString = $"{perc:F0}%";
|
||||
|
||||
float px = pieRect.X + pieRect.Width / 2;
|
||||
float py = pieRect.Y + pieRect.Height / 2;
|
||||
|
||||
double angle = item.StartPos + item.SweepSize / 2;
|
||||
double rads = angle / 180.0 * Math.PI;
|
||||
|
||||
px += (float)(Math.Cos(rads) * perimeter / 3);
|
||||
py += (float)(Math.Sin(rads) * perimeter / 3);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30 - 1, py - 20, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30 + 1, py - 20, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30, py - 20 - 1, 60, 40), sfp);
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.Gray,
|
||||
new RectangleF(px - 30, py - 20 + 1, 60, 40), sfp);
|
||||
|
||||
|
||||
grp.DrawString(percString, fnt, Brushes.White,
|
||||
new RectangleF(px - 30, py - 20, 60, 40), sfp);
|
||||
}
|
||||
|
||||
if (pen == null)
|
||||
pen = new Pen(_borderColor, 0.5f);
|
||||
|
||||
grp.FillRectangle(brs, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10);
|
||||
grp.DrawRectangle(pen, perimeter + _bufferSpace, i * _legendFontHeight + 15, 10, 10);
|
||||
|
||||
grp.DrawString(item.Label, fnt,
|
||||
Brushes.Black, perimeter + _bufferSpace + 20, i * _legendFontHeight + 13);
|
||||
|
||||
grp.DrawString(item.Value.ToString("#,###.##"), fnt,
|
||||
Brushes.Black, perimeter + _bufferSpace + 200, i * _legendFontHeight + 13, sf);
|
||||
}
|
||||
finally
|
||||
{
|
||||
brs?.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < _chartItems.Count; i++)
|
||||
{
|
||||
DataItem item = _chartItems[i];
|
||||
try
|
||||
{
|
||||
grp.DrawPie(new Pen(_borderColor, 0.5f), pieRect, item.StartPos, item.SweepSize);
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
//draws the border around Pie
|
||||
using (Pen pen2 = new Pen(_borderColor, 2))
|
||||
{
|
||||
grp.DrawEllipse(pen2, pieRect);
|
||||
}
|
||||
|
||||
//draw border around legend
|
||||
using (Pen pen1 = new Pen(_borderColor, 1))
|
||||
{
|
||||
grp.DrawRectangle(pen1, perimeter + _bufferSpace - 10, 10, 220,
|
||||
_chartItems.Count * _legendFontHeight + 25);
|
||||
}
|
||||
|
||||
//Draw Total under legend
|
||||
using (Font fntb = new Font(_legendFontStyle, _legendFontSize, FontStyle.Bold))
|
||||
{
|
||||
grp.DrawString("Total", fntb,
|
||||
Brushes.Black, perimeter + _bufferSpace + 30, (_chartItems.Count + 1) * _legendFontHeight, sf);
|
||||
grp.DrawString(_total.ToString("#,###.##"), fntb,
|
||||
Brushes.Black, perimeter + _bufferSpace + 200, (_chartItems.Count + 1) * _legendFontHeight, sf);
|
||||
}
|
||||
|
||||
grp.SmoothingMode = SmoothingMode.AntiAlias;
|
||||
}
|
||||
finally
|
||||
{
|
||||
sf.Dispose();
|
||||
grp.Dispose();
|
||||
sfp?.Dispose();
|
||||
fnt?.Dispose();
|
||||
pen?.Dispose();
|
||||
}
|
||||
|
||||
return bmp;
|
||||
}
|
||||
|
||||
//*********************************************************************
|
||||
//
|
||||
// This method calculates the space required to draw the chart legend.
|
||||
//
|
||||
//*********************************************************************
|
||||
|
||||
private void CalculateLegendWidthHeight()
|
||||
{
|
||||
Font fontLegend = new Font(_legendFontStyle, _legendFontSize);
|
||||
_legendFontHeight = fontLegend.Height + 3;
|
||||
_legendHeight = fontLegend.Height * (_chartItems.Count + 1);
|
||||
if (_legendHeight > _perimeter) _perimeter = _legendHeight;
|
||||
|
||||
_legendWidth = _perimeter + _bufferSpace;
|
||||
fontLegend.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,547 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Server.Accounting;
|
||||
using Server.Engines.ConPVP;
|
||||
using Server.Engines.Help;
|
||||
using Server.Factions;
|
||||
using Server.Mobiles;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Engines.Reports
|
||||
{
|
||||
public class Reports
|
||||
{
|
||||
public static bool Enabled = false;
|
||||
|
||||
private static DateTime m_GenerateTime;
|
||||
|
||||
private static SnapshotHistory m_StatsHistory;
|
||||
|
||||
public static StaffHistory StaffHistory{ get; private set; }
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
m_StatsHistory = new SnapshotHistory();
|
||||
m_StatsHistory.Load();
|
||||
|
||||
StaffHistory = new StaffHistory();
|
||||
StaffHistory.Load();
|
||||
|
||||
DateTime now = DateTime.UtcNow;
|
||||
|
||||
DateTime date = now.Date;
|
||||
TimeSpan timeOfDay = now.TimeOfDay;
|
||||
|
||||
m_GenerateTime = date + TimeSpan.FromHours(Math.Ceiling(timeOfDay.TotalHours));
|
||||
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(0.5), TimeSpan.FromMinutes(0.5), CheckRegenerate);
|
||||
}
|
||||
|
||||
public static void CheckRegenerate()
|
||||
{
|
||||
if (DateTime.UtcNow < m_GenerateTime)
|
||||
return;
|
||||
|
||||
Generate();
|
||||
m_GenerateTime += TimeSpan.FromHours(1.0);
|
||||
}
|
||||
|
||||
public static void Generate()
|
||||
{
|
||||
Snapshot ss = new Snapshot();
|
||||
|
||||
ss.TimeStamp = DateTime.UtcNow;
|
||||
|
||||
FillSnapshot(ss);
|
||||
|
||||
m_StatsHistory.Snapshots.Add(ss);
|
||||
StaffHistory.QueueStats.Add(new QueueStatus(PageQueue.List.Count));
|
||||
|
||||
ThreadPool.QueueUserWorkItem(UpdateOutput, ss);
|
||||
}
|
||||
|
||||
private static void UpdateOutput(object state)
|
||||
{
|
||||
m_StatsHistory.Save();
|
||||
StaffHistory.Save();
|
||||
|
||||
HtmlRenderer renderer = new HtmlRenderer("stats", (Snapshot)state, m_StatsHistory);
|
||||
renderer.Render();
|
||||
renderer.Upload();
|
||||
|
||||
renderer = new HtmlRenderer("staff", StaffHistory);
|
||||
renderer.Render();
|
||||
renderer.Upload();
|
||||
}
|
||||
|
||||
public static void FillSnapshot(Snapshot ss)
|
||||
{
|
||||
ss.Children.Add(CompileGeneralStats());
|
||||
ss.Children.Add(CompilePCByDL());
|
||||
ss.Children.Add(CompileTop15());
|
||||
ss.Children.Add(CompileDislikedArenas());
|
||||
ss.Children.Add(CompileStatChart());
|
||||
|
||||
PersistableObject[] obs = CompileSkillReports();
|
||||
|
||||
for (int i = 0; i < obs.Length; ++i)
|
||||
ss.Children.Add(obs[i]);
|
||||
|
||||
obs = CompileFactionReports();
|
||||
|
||||
for (int i = 0; i < obs.Length; ++i)
|
||||
ss.Children.Add(obs[i]);
|
||||
}
|
||||
|
||||
public static Report CompileGeneralStats()
|
||||
{
|
||||
Report report = new Report("General Stats", "200");
|
||||
|
||||
report.Columns.Add("50%", "left");
|
||||
report.Columns.Add("50%", "left");
|
||||
|
||||
int npcs = 0, players = 0;
|
||||
|
||||
foreach (Mobile mob in World.Mobiles.Values)
|
||||
if (mob.Player)
|
||||
++players;
|
||||
else
|
||||
++npcs;
|
||||
|
||||
report.Items.Add("NPCs", npcs, "N0");
|
||||
report.Items.Add("Players", players, "N0");
|
||||
report.Items.Add("Clients", NetState.Instances.Count, "N0");
|
||||
report.Items.Add("Accounts", Accounts.Count, "N0");
|
||||
report.Items.Add("Items", World.Items.Count, "N0");
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private static Chart CompilePCByDL()
|
||||
{
|
||||
BarGraph chart = new BarGraph("Player Count By Dueling Level", "graphs_pc_by_dl", 5, "Dueling Level", "Players",
|
||||
BarGraphRenderMode.Bars);
|
||||
|
||||
int lastLevel = -1;
|
||||
ChartItem lastItem = null;
|
||||
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
if (ladder == null)
|
||||
return chart;
|
||||
|
||||
List<LadderEntry> entries = ladder.Entries;
|
||||
|
||||
for (int i = entries.Count - 1; i >= 0; --i)
|
||||
{
|
||||
LadderEntry entry = entries[i];
|
||||
int level = Ladder.GetLevel(entry.Experience);
|
||||
|
||||
if (lastItem == null || level != lastLevel)
|
||||
{
|
||||
chart.Items.Add(lastItem = new ChartItem(level.ToString(), 1));
|
||||
lastLevel = level;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastItem.Value++;
|
||||
}
|
||||
}
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
private static Report CompileTop15()
|
||||
{
|
||||
Report report = new Report("Top 15 Duelists", "80%");
|
||||
|
||||
report.Columns.Add("6%", "center", "Rank");
|
||||
report.Columns.Add("6%", "center", "Level");
|
||||
report.Columns.Add("6%", "center", "Guild");
|
||||
report.Columns.Add("70%", "left", "Name");
|
||||
report.Columns.Add("6%", "center", "Wins");
|
||||
report.Columns.Add("6%", "center", "Losses");
|
||||
|
||||
Ladder ladder = Ladder.Instance;
|
||||
|
||||
if (ladder != null)
|
||||
{
|
||||
List<LadderEntry> entries = ladder.Entries;
|
||||
|
||||
for (int i = 0; i < entries.Count && i < 15; ++i)
|
||||
{
|
||||
LadderEntry entry = entries[i];
|
||||
int level = Ladder.GetLevel(entry.Experience);
|
||||
string guild = "";
|
||||
|
||||
if (entry.Mobile.Guild != null)
|
||||
guild = entry.Mobile.Guild.Abbreviation;
|
||||
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(LadderGump.Rank(entry.Index + 1));
|
||||
item.Values.Add(level.ToString(), "N0");
|
||||
item.Values.Add(guild);
|
||||
item.Values.Add(entry.Mobile.Name);
|
||||
item.Values.Add(entry.Wins.ToString(), "N0");
|
||||
item.Values.Add(entry.Losses.ToString(), "N0");
|
||||
|
||||
report.Items.Add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
private static Chart CompileDislikedArenas()
|
||||
{
|
||||
PieChart chart = new PieChart("Most Disliked Arenas", "graphs_arenas_disliked", false);
|
||||
|
||||
Preferences prefs = Preferences.Instance;
|
||||
|
||||
if (prefs == null)
|
||||
return chart;
|
||||
|
||||
List<Arena> arenas = Arena.Arenas;
|
||||
|
||||
for (int i = 0; i < arenas.Count; ++i)
|
||||
{
|
||||
Arena arena = arenas[i];
|
||||
|
||||
string name = arena.Name;
|
||||
|
||||
if (name != null)
|
||||
chart.Items.Add(name, 0);
|
||||
}
|
||||
|
||||
List<PreferencesEntry> entries = prefs.Entries;
|
||||
|
||||
for (int i = 0; i < entries.Count; ++i)
|
||||
{
|
||||
PreferencesEntry entry = entries[i];
|
||||
List<string> list = entry.Disliked;
|
||||
|
||||
for (int j = 0; j < list.Count; ++j)
|
||||
{
|
||||
string disliked = list[j];
|
||||
|
||||
for (int k = 0; k < chart.Items.Count; ++k)
|
||||
{
|
||||
ChartItem item = chart.Items[k];
|
||||
|
||||
if (item.Name == disliked)
|
||||
{
|
||||
++item.Value;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static Chart CompileStatChart()
|
||||
{
|
||||
PieChart chart = new PieChart("Stat Distribution", "graphs_strdexint_distrib", true);
|
||||
|
||||
ChartItem strItem = new ChartItem("Strength", 0);
|
||||
ChartItem dexItem = new ChartItem("Dexterity", 0);
|
||||
ChartItem intItem = new ChartItem("Intelligence", 0);
|
||||
|
||||
foreach (Mobile mob in World.Mobiles.Values)
|
||||
if (mob.RawStatTotal == mob.StatCap && mob is PlayerMobile)
|
||||
{
|
||||
strItem.Value += mob.RawStr;
|
||||
dexItem.Value += mob.RawDex;
|
||||
intItem.Value += mob.RawInt;
|
||||
}
|
||||
|
||||
chart.Items.Add(strItem);
|
||||
chart.Items.Add(dexItem);
|
||||
chart.Items.Add(intItem);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static SkillDistribution[] GetSkillDistribution()
|
||||
{
|
||||
int skip = Core.ML ? 0 : Core.SE ? 1 : Core.AOS ? 3 : 6;
|
||||
|
||||
SkillDistribution[] distribs = new SkillDistribution[SkillInfo.Table.Length - skip];
|
||||
|
||||
for (int i = 0; i < distribs.Length; ++i)
|
||||
distribs[i] = new SkillDistribution(SkillInfo.Table[i]);
|
||||
|
||||
foreach (Mobile mob in World.Mobiles.Values)
|
||||
if (mob.SkillsTotal >= 1500 && mob.SkillsTotal <= 7200 && mob is PlayerMobile)
|
||||
{
|
||||
Skills skills = mob.Skills;
|
||||
|
||||
for (int i = 0; i < skills.Length - skip; ++i)
|
||||
{
|
||||
Skill skill = skills[i];
|
||||
|
||||
if (skill.BaseFixedPoint >= 1000)
|
||||
distribs[i].m_NumberOfGMs++;
|
||||
}
|
||||
}
|
||||
|
||||
return distribs;
|
||||
}
|
||||
|
||||
public static PersistableObject[] CompileSkillReports()
|
||||
{
|
||||
SkillDistribution[] distribs = GetSkillDistribution();
|
||||
|
||||
Array.Sort(distribs);
|
||||
|
||||
return new PersistableObject[] { CompileSkillChart(distribs), CompileSkillReport(distribs) };
|
||||
}
|
||||
|
||||
public static Report CompileSkillReport(SkillDistribution[] distribs)
|
||||
{
|
||||
Report report = new Report("Skill Report", "300");
|
||||
|
||||
report.Columns.Add("70%", "left", "Name");
|
||||
report.Columns.Add("30%", "center", "GMs");
|
||||
|
||||
for (int i = 0; i < distribs.Length; ++i)
|
||||
report.Items.Add(distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs, "N0");
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
public static Chart CompileSkillChart(SkillDistribution[] distribs)
|
||||
{
|
||||
PieChart chart = new PieChart("GM Skill Distribution", "graphs_skill_distrib", true);
|
||||
|
||||
for (int i = 0; i < 12; ++i)
|
||||
chart.Items.Add(distribs[i].m_Skill.Name, distribs[i].m_NumberOfGMs);
|
||||
|
||||
int rem = 0;
|
||||
|
||||
for (int i = 12; i < distribs.Length; ++i)
|
||||
rem += distribs[i].m_NumberOfGMs;
|
||||
|
||||
chart.Items.Add("Other", rem);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static PersistableObject[] CompileFactionReports()
|
||||
{
|
||||
return new PersistableObject[]
|
||||
{
|
||||
CompileFactionMembershipChart(), CompileFactionReport(), CompileFactionTownReport(), CompileSigilReport(),
|
||||
CompileFactionLeaderboard()
|
||||
};
|
||||
}
|
||||
|
||||
public static Chart CompileFactionMembershipChart()
|
||||
{
|
||||
PieChart chart = new PieChart("Faction Membership", "graphs_faction_membership", true);
|
||||
|
||||
List<Faction> factions = Faction.Factions;
|
||||
|
||||
for (int i = 0; i < factions.Count; ++i)
|
||||
chart.Items.Add(factions[i].Definition.FriendlyName, factions[i].Members.Count);
|
||||
|
||||
return chart;
|
||||
}
|
||||
|
||||
public static Report CompileFactionLeaderboard()
|
||||
{
|
||||
Report report = new Report("Faction Leaderboard", "60%");
|
||||
|
||||
report.Columns.Add("28%", "center", "Name");
|
||||
report.Columns.Add("28%", "center", "Faction");
|
||||
report.Columns.Add("28%", "center", "Office");
|
||||
report.Columns.Add("16%", "center", "Kill Points");
|
||||
|
||||
List<PlayerState> list = new List<PlayerState>();
|
||||
|
||||
List<Faction> factions = Faction.Factions;
|
||||
|
||||
for (int i = 0; i < factions.Count; ++i)
|
||||
{
|
||||
Faction faction = factions[i];
|
||||
|
||||
list.AddRange(faction.Members);
|
||||
}
|
||||
|
||||
list.Sort();
|
||||
list.Reverse();
|
||||
|
||||
for (int i = 0; i < list.Count && i < 15; ++i)
|
||||
{
|
||||
PlayerState pl = list[i];
|
||||
|
||||
string office;
|
||||
|
||||
if (pl.Faction.Commander == pl.Mobile)
|
||||
office = "Commanding Lord";
|
||||
else if (pl.Finance != null)
|
||||
office = $"{pl.Finance.Definition.FriendlyName} Finance Minister";
|
||||
else if (pl.Sheriff != null)
|
||||
office = $"{pl.Sheriff.Definition.FriendlyName} Sheriff";
|
||||
else
|
||||
office = "";
|
||||
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(pl.Mobile.Name);
|
||||
item.Values.Add(pl.Faction.Definition.FriendlyName);
|
||||
item.Values.Add(office);
|
||||
item.Values.Add(pl.KillPoints.ToString(), "N0");
|
||||
|
||||
report.Items.Add(item);
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
public static Report CompileFactionReport()
|
||||
{
|
||||
Report report = new Report("Faction Statistics", "80%");
|
||||
|
||||
report.Columns.Add("20%", "center", "Name");
|
||||
report.Columns.Add("20%", "center", "Commander");
|
||||
report.Columns.Add("15%", "center", "Members");
|
||||
report.Columns.Add("15%", "center", "Merchants");
|
||||
report.Columns.Add("15%", "center", "Kill Points");
|
||||
report.Columns.Add("15%", "center", "Silver");
|
||||
|
||||
List<Faction> factions = Faction.Factions;
|
||||
|
||||
for (int i = 0; i < factions.Count; ++i)
|
||||
{
|
||||
Faction faction = factions[i];
|
||||
List<PlayerState> members = faction.Members;
|
||||
|
||||
int totalKillPoints = 0;
|
||||
int totalMerchants = 0;
|
||||
|
||||
for (int j = 0; j < members.Count; ++j)
|
||||
{
|
||||
totalKillPoints += members[j].KillPoints;
|
||||
|
||||
if (members[j].MerchantTitle != MerchantTitle.None)
|
||||
++totalMerchants;
|
||||
}
|
||||
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(faction.Definition.FriendlyName);
|
||||
item.Values.Add(faction.Commander == null ? "" : faction.Commander.Name);
|
||||
item.Values.Add(faction.Members.Count.ToString(), "N0");
|
||||
item.Values.Add(totalMerchants.ToString(), "N0");
|
||||
item.Values.Add(totalKillPoints.ToString(), "N0");
|
||||
item.Values.Add(faction.Silver.ToString(), "N0");
|
||||
|
||||
report.Items.Add(item);
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
public static Report CompileSigilReport()
|
||||
{
|
||||
Report report = new Report("Faction Town Sigils", "50%");
|
||||
|
||||
report.Columns.Add("35%", "center", "Town");
|
||||
report.Columns.Add("35%", "center", "Controller");
|
||||
report.Columns.Add("30%", "center", "Capturable");
|
||||
|
||||
List<Sigil> sigils = Sigil.Sigils;
|
||||
|
||||
for (int i = 0; i < sigils.Count; ++i)
|
||||
{
|
||||
Sigil sigil = sigils[i];
|
||||
|
||||
string controller = "Unknown";
|
||||
|
||||
if (sigil.RootParent is Mobile mob)
|
||||
{
|
||||
Faction faction = Faction.Find(mob);
|
||||
|
||||
if (faction != null)
|
||||
controller = faction.Definition.FriendlyName;
|
||||
}
|
||||
else if (sigil.LastMonolith?.Faction != null)
|
||||
{
|
||||
controller = sigil.LastMonolith.Faction.Definition.FriendlyName;
|
||||
}
|
||||
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(sigil.Town == null ? "" : sigil.Town.Definition.FriendlyName);
|
||||
item.Values.Add(controller);
|
||||
item.Values.Add(sigil.IsPurifying ? "No" : "Yes");
|
||||
|
||||
report.Items.Add(item);
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
public static Report CompileFactionTownReport()
|
||||
{
|
||||
Report report = new Report("Faction Towns", "80%");
|
||||
|
||||
report.Columns.Add("20%", "center", "Name");
|
||||
report.Columns.Add("20%", "center", "Owner");
|
||||
report.Columns.Add("17%", "center", "Sheriff");
|
||||
report.Columns.Add("17%", "center", "Finance Minister");
|
||||
report.Columns.Add("13%", "center", "Silver");
|
||||
report.Columns.Add("13%", "center", "Prices");
|
||||
|
||||
List<Town> towns = Town.Towns;
|
||||
|
||||
for (int i = 0; i < towns.Count; ++i)
|
||||
{
|
||||
Town town = towns[i];
|
||||
|
||||
string prices = "Normal";
|
||||
|
||||
if (town.Tax < 0)
|
||||
prices = town.Tax + "%";
|
||||
else if (town.Tax > 0)
|
||||
prices = "+" + town.Tax + "%";
|
||||
|
||||
ReportItem item = new ReportItem();
|
||||
|
||||
item.Values.Add(town.Definition.FriendlyName);
|
||||
item.Values.Add(town.Owner == null ? "Neutral" : town.Owner.Definition.FriendlyName);
|
||||
item.Values.Add(town.Sheriff == null ? "" : town.Sheriff.Name);
|
||||
item.Values.Add(town.Finance == null ? "" : town.Finance.Name);
|
||||
item.Values.Add(town.Silver.ToString(), "N0");
|
||||
item.Values.Add(prices);
|
||||
|
||||
report.Items.Add(item);
|
||||
}
|
||||
|
||||
return report;
|
||||
}
|
||||
|
||||
public class SkillDistribution : IComparable<SkillDistribution>
|
||||
{
|
||||
public int m_NumberOfGMs;
|
||||
public SkillInfo m_Skill;
|
||||
|
||||
public SkillDistribution(SkillInfo skill)
|
||||
{
|
||||
m_Skill = skill;
|
||||
}
|
||||
|
||||
public int CompareTo(SkillDistribution sd)
|
||||
{
|
||||
return sd?.m_NumberOfGMs ?? 0 - m_NumberOfGMs;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue