Adds configuration system. (#125)

This commit is contained in:
Kamron Batman 2020-05-02 16:44:05 -07:00 committed by GitHub
parent 2b4a6e1de1
commit 5b01754e3e
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 409 additions and 420 deletions

3
.gitignore vendored
View file

@ -2,6 +2,7 @@
/Distribution/ModernUO
/Distribution/ModernUO.*
/Distribution/Assemblies
/Distribution/Configuration
/Distribution/Logs
/Distribution/Backups
/Distribution/Saves
@ -41,4 +42,4 @@
.DS_Store
/packages/*
!/packages/do_not_delete
!do_not_delete

View file

View file

@ -1,84 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Server.Mobiles;
using Server.Network;
namespace Server.Commands
{
public class ConvertPlayers
{
public static void Initialize()
{
CommandSystem.Register("ConvertPlayers", AccessLevel.Administrator, Convert_OnCommand);
}
public static void Convert_OnCommand(CommandEventArgs e)
{
e.Mobile.SendMessage(
"Converting all players to PlayerMobile. You will be disconnected. Please Restart the server after the world has finished saving.");
List<Mobile> mobs = new List<Mobile>(World.Mobiles.Values);
int count = 0;
foreach (Mobile m in mobs)
if (m.Player && !(m is PlayerMobile))
{
count++;
m.NetState?.Dispose();
PlayerMobile pm = new PlayerMobile(m.Serial);
pm.DefaultMobileInit();
List<Item> copy = new List<Item>(m.Items);
for (int i = 0; i < copy.Count; i++)
pm.AddItem(copy[i]);
CopyProps(pm, m);
for (int i = 0; i < m.Skills.Length; i++)
{
pm.Skills[i].Base = m.Skills[i].Base;
pm.Skills[i].SetLockNoRelay(m.Skills[i].Lock);
}
World.Mobiles[m.Serial] = pm;
}
if (count > 0)
{
NetState.ProcessDisposedQueue();
World.Save();
Console.WriteLine("{0} players have been converted to PlayerMobile. {1}.", count,
Core.Service ? "The server is now restarting" : "Press any key to restart the server");
if (!Core.Service)
Console.ReadKey(true);
Core.Kill(true);
}
else
{
e.Mobile.SendMessage("Couldn't find any Players to convert.");
}
}
private static readonly PropertyInfo[] _mobProps =
typeof(Mobile).GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(prop => prop.CanRead && prop.CanWrite).ToArray();
private static void CopyProps(Mobile to, Mobile from)
{
foreach (PropertyInfo prop in _mobProps)
try
{
prop.SetValue(to, prop.GetValue(from, null), null);
}
catch
{
// ignored
}
}
}
}

View file

@ -0,0 +1,75 @@
using System.IO;
using System.Text.Json.Serialization;
using MimeKit;
using Server.Json;
namespace Server.Configurations
{
public static class EmailConfiguration
{
public static readonly bool EmailEnabled;
public static readonly MailboxAddress FromAddress;
public static readonly MailboxAddress CrashAddress;
public static readonly MailboxAddress SpeechLogPageAddress;
public static readonly string EmailServer;
public static readonly int EmailPort;
public static readonly string EmailServerUsername;
public static readonly string EmailServerPassword;
public static readonly int EmailSendRetryCount = 5; // seconds
public static readonly int EmailSendRetryDelay = 2; // seconds
static EmailConfiguration()
{
string filePath = Path.Join(Core.BaseDirectory, "Configuration/email-settings.json");
Settings settings = JsonConfig.Deserialize<Settings>(filePath) ?? new Settings();
if (settings.emailServer == null || settings.fromAddress == null)
{
JsonConfig.Serialize(filePath, settings);
return;
}
EmailEnabled = true;
FromAddress = new MailboxAddress(settings.fromName, settings.fromAddress);
CrashAddress = new MailboxAddress(settings.crashName, settings.crashAddress);
SpeechLogPageAddress = new MailboxAddress(settings.speechLogPageName, settings.speechLogPageAddress);
EmailServer = settings.emailServer;
EmailPort = settings.emailPort;
EmailServerUsername = settings.emailUsername;
EmailServerPassword = settings.emailPassword;
}
internal class Settings
{
[JsonPropertyName("fromAddress")]
internal string fromAddress { get; set; }
[JsonPropertyName("fromName")]
internal string fromName { get; set; }
[JsonPropertyName("crashAddress")]
internal string crashAddress { get; set; }
[JsonPropertyName("crashName")]
internal string crashName { get; set; }
[JsonPropertyName("speechLogPageAddress")]
internal string speechLogPageAddress { get; set; }
[JsonPropertyName("speechLogPageName")]
internal string speechLogPageName { get; set; }
[JsonPropertyName("emailServer")]
internal string emailServer { get; set; }
[JsonPropertyName("emailPort")]
internal int emailPort { get; set; }
[JsonPropertyName("emailUsername")]
internal string emailUsername { get; set; }
[JsonPropertyName("emailPassword")]
internal string emailPassword { get; set; }
}
}
}

View file

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using Server.Configurations;
using Server.Misc;
using Server.Mobiles;
using Server.Network;
@ -227,7 +228,7 @@ namespace Server.Engines.Help
entry.Sender.SendMessage(
"We are sorry, but no staff members are currently available to assist you. Your page will remain in the queue until one becomes available, or until you cancel it manually.");
if (Email.FROM_ADDRESS != null && Email.SPEECH_LOG_PAGE_ADDRESS != null && entry.SpeechLog != null)
if (entry.SpeechLog != null)
Email.SendQueueEmail(entry, GetPageTypeName(entry.Type));
}
}

View file

@ -7,7 +7,7 @@ namespace Server.Misc
{
public static void Initialize()
{
if (Accounts.Count == 0 && !Core.Service)
if (Accounts.Count == 0)
{
Console.WriteLine("This server has no accounts.");
Console.Write("Do you want to create the owner account now? (y/n)");
@ -36,4 +36,4 @@ namespace Server.Misc
}
}
}
}
}

View file

@ -41,8 +41,7 @@ namespace Server.Misc
{
Console.Write("Crash: Sending email...");
if (Email.FROM_ADDRESS != null && Email.CRASH_ADDRESS != null)
Email.SendCrashEmail(filePath);
Email.SendCrashEmail(filePath);
}
private static string GetRoot()
@ -229,8 +228,7 @@ namespace Server.Misc
Console.WriteLine("done");
if (Email.FROM_ADDRESS != null && Email.CRASH_ADDRESS != null)
SendEmail(filePath);
SendEmail(filePath);
}
catch
{

View file

@ -4,22 +4,13 @@ using System.Threading.Tasks;
using MailKit.Net.Smtp;
using MimeKit;
using Server.Accounting;
using Server.Configurations;
using Server.Engines.Help;
namespace Server.Misc
{
public static class Email
{
public static readonly MailboxAddress FROM_ADDRESS = new MailboxAddress(Configuration.Instance.emailSettings.FromName, Configuration.Instance.emailSettings.FromAddress);
public static readonly MailboxAddress CRASH_ADDRESS = new MailboxAddress(Configuration.Instance.emailSettings.crashName, Configuration.Instance.emailSettings.crashAddress);
public static readonly MailboxAddress SPEECH_LOG_PAGE_ADDRESS = new MailboxAddress(Configuration.Instance.emailSettings.speechLogPageName, Configuration.Instance.emailSettings.speechLogPageAddress);
public static readonly string EMAIL_SERVER = Configuration.Instance.emailSettings.emailServer;
public static readonly int EMAIL_PORT = Configuration.Instance.emailSettings.emailPort;
public static readonly string EMAIL_SERVER_USERNAME = Configuration.Instance.emailSettings.emailUsername;
public static readonly string EMAIL_SERVER_PASSWORD = Configuration.Instance.emailSettings.emailPassword;
public static readonly int RETRY_SEND_EMAIL_COUNT = 5;
public static readonly int SEND_DELAY_SECONDS = 2;
/// <summary>
/// Sends Queue-Page request using Email
/// </summary>
@ -27,12 +18,14 @@ namespace Server.Misc
/// <param name="pageType"></param>
public static void SendQueueEmail(PageEntry entry, string pageType)
{
if (!EmailConfiguration.EmailEnabled) return;
Mobile sender = entry.Sender;
DateTime time = DateTime.UtcNow;
var message = new MimeMessage();
message.From.Add(FROM_ADDRESS);
message.To.Add(SPEECH_LOG_PAGE_ADDRESS);
message.From.Add(EmailConfiguration.FromAddress);
message.To.Add(EmailConfiguration.SpeechLogPageAddress);
message.Subject = "ModernUO Speech Log Page Forwarding";
using (StringWriter writer = new StringWriter())
@ -77,9 +70,11 @@ namespace Server.Misc
/// <param name="filePath"></param>
public static void SendCrashEmail(string filePath)
{
if (EmailConfiguration.EmailEnabled) return;
var message = new MimeMessage();
message.From.Add(FROM_ADDRESS);
message.To.Add(CRASH_ADDRESS);
message.From.Add(EmailConfiguration.FromAddress);
message.To.Add(EmailConfiguration.CrashAddress);
message.Subject = "Automated ModernUO Crash Report";
var builder = new BodyBuilder
{
@ -96,19 +91,21 @@ namespace Server.Misc
/// <param name="message"></param>
private static async void SendAsync(MimeMessage message)
{
if (!EmailConfiguration.EmailEnabled) return;
DateTime now = DateTime.UtcNow;
string messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EMAIL_SERVER}>";
string messageID = $"<{now:yyyyMMdd}.{now:HHmmssff}@{EmailConfiguration.EmailServer}>";
message.Headers.Add("Message-ID", messageID);
message.From.Add(FROM_ADDRESS);
message.From.Add(EmailConfiguration.FromAddress);
int delay = SEND_DELAY_SECONDS;
int delay = EmailConfiguration.EmailSendRetryDelay;
for (int i = 0; i < RETRY_SEND_EMAIL_COUNT; i++)
for (int i = 0; i < EmailConfiguration.EmailSendRetryCount; i++)
try
{
using SmtpClient client = new SmtpClient();
await client.ConnectAsync(EMAIL_SERVER, EMAIL_PORT, true);
await client.AuthenticateAsync(EMAIL_SERVER_USERNAME, EMAIL_SERVER_PASSWORD);
await client.ConnectAsync(EmailConfiguration.EmailServer, EmailConfiguration.EmailPort, true);
await client.AuthenticateAsync(EmailConfiguration.EmailServerUsername, EmailConfiguration.EmailServerPassword);
await client.SendAsync(message);
await client.DisconnectAsync(true);
return;

View file

@ -1,133 +0,0 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: Configuration.cs - Created: 2019/10/04 - Updated: 2020/01/19 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server
{
public class Configuration
{
private static Configuration m_Configuration;
public static Configuration Instance => m_Configuration ??= ReadConfiguration();
[JsonPropertyName("dataDirectories")]
public List<string> DataDirectories { get; set; } = new List<string>();
[JsonPropertyName("emailSettings")]
public EmailSettings emailSettings { get; set; } = new EmailSettings();
private static string FilePath => Path.Join(Core.BaseDirectory, "Data/modernuo.json");
private static void PromptDataDirectories(Configuration config)
{
Console.WriteLine("Please enter the Ultima Online directory:");
string directory;
do
{
Console.Write("> ");
directory = Console.ReadLine();
} while (!Directory.Exists(directory));
config.DataDirectories.Add(directory);
}
private static Configuration ReadConfiguration()
{
var relPath = new Uri($"{Core.BaseDirectory}/").MakeRelativeUri(new Uri(FilePath)).ToString();
Console.Write($"Reading configuration from {relPath}...");
Configuration config;
if (File.Exists(FilePath))
{
using var fs = new FileStream(FilePath, FileMode.Open, FileAccess.Read, FileShare.Read);
Span<byte> configBytes = stackalloc byte[(int)fs.Length];
fs.Read(configBytes);
config = JsonSerializer.Deserialize<Configuration>(Utility.UTF8WithEncoding.GetString(configBytes));
Console.WriteLine("done");
}
else
{
Console.WriteLine("not found");
config = new Configuration();
}
// TODO: Extend with a config read verification function that can be extended.
if (config.DataDirectories.Count == 0)
{
PromptDataDirectories(config);
config.Flush();
}
return config;
}
public void Flush()
{
using var fs = new FileStream(FilePath, FileMode.OpenOrCreate, FileAccess.Write, FileShare.Write);
var configJson = JsonSerializer.Serialize(this, new JsonSerializerOptions { WriteIndented = true });
Span<byte> data = stackalloc byte[Utility.UTF8WithEncoding.GetMaxByteCount(configJson.Length)];
var bytesWritten = Utility.UTF8WithEncoding.GetBytes(configJson, data);
fs.Write(data.Slice(0, bytesWritten));
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Configuration saved to {FilePath}");
Console.ResetColor();
}
}
// TODO: Make configuration pluggable. Move this to scripts
public class EmailSettings
{
[JsonPropertyName("fromAddress")]
public string FromAddress { get; set; }
[JsonPropertyName("fromName")]
public string FromName { get; set; }
[JsonPropertyName("crashAddress")]
public string crashAddress { get; set; }
[JsonPropertyName("crashName")]
public string crashName { get; set; }
[JsonPropertyName("speechLogPageAddress")]
public string speechLogPageAddress { get; set; }
[JsonPropertyName("speechLogPageName")]
public string speechLogPageName { get; set; }
[JsonPropertyName("emailServer")]
public string emailServer { get; set; }
[JsonPropertyName("emailPort")]
public int emailPort { get; set; }
[JsonPropertyName("emailUsername")]
public string emailUsername { get; set; }
[JsonPropertyName("emailPassword")]
public string emailPassword { get; set; }
}
}

View file

@ -0,0 +1,110 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: Configuration.cs - Created: 2019/10/04 - Updated: 2020/01/19 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Collections.Generic;
using System.IO;
using System.Text.Json.Serialization;
using Server.Json;
namespace Server
{
public static class ServerConfiguration
{
private const string m_RelPath = "Configuration/modernuo.json";
private static readonly string m_FilePath = Path.Join(Core.BaseDirectory, m_RelPath);
private static ServerSettings m_Settings;
public static List<string> DataDirectories => m_Settings.dataDirectories;
public static Dictionary<string, string> Settings => m_Settings.settings;
public static Dictionary<string, object> Metadata => m_Settings.metadata;
public static void LoadConfiguration()
{
bool updated = false;
if (File.Exists(m_FilePath))
{
Console.Write($"Core: Reading configuration from {m_RelPath}...");
m_Settings = JsonConfig.Deserialize<ServerSettings>(m_FilePath);
if (m_Settings == null)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("failed");
Console.ResetColor();
throw new Exception("Core: Server configuration failed to deserialize.");
}
Console.WriteLine("done");
Console.WriteLine("Settings: {0}", m_Settings.settings["stuff"]);
}
else
{
updated = true;
m_Settings = new ServerSettings();
}
if (m_Settings.dataDirectories.Count == 0)
{
updated = true;
Console.WriteLine("Core: Server configuration is missing data directories.");
m_Settings.dataDirectories.Add(GetDataDirectory());
}
if (updated)
SaveConfiguration();
}
internal class ServerSettings
{
[JsonPropertyName("dataDirectories")]
public List<string> dataDirectories { get; set; } = new List<string>();
[JsonPropertyName("settings")]
public Dictionary<string, string> settings { get; set; } = new Dictionary<string, string>();
[JsonExtensionData]
public Dictionary<string, object> metadata { get; set; } = new Dictionary<string, object>();
}
private static string GetDataDirectory()
{
Console.WriteLine("Please enter the Ultima Online directory:");
string directory;
do
{
Console.Write("> ");
directory = Console.ReadLine();
} while (!Directory.Exists(directory));
return directory;
}
public static void SaveConfiguration()
{
JsonConfig.Serialize(m_FilePath, m_Settings);
Console.ForegroundColor = ConsoleColor.Green;
Console.WriteLine($"Core: Configuration saved to {m_RelPath}.");
Console.ResetColor();
}
}
}

View file

@ -0,0 +1,35 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MapConverter.cs - Created: 2020/04/12 - Updated: 2020/05/02 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class MapConverter : JsonConverter<Map>
{
public override Map Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Map.Parse(reader.GetString());
public override void Write(Utf8JsonWriter writer, Map value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.Name);
}
}

View file

@ -0,0 +1,67 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: MapConverter.cs - Created: 2020/04/12 - Updated: 2020/05/02 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class Point3dConverter : JsonConverter<Point3D>
{
public override Point3D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
throw new JsonException("Point3d must be an array of x, y, z");
var data = new int[3];
var count = 0;
while (true)
{
reader.Read();
if (reader.TokenType == JsonTokenType.EndArray)
break;
if (reader.TokenType == JsonTokenType.Number)
{
if (count < 3)
data[count] = reader.GetInt32();
count++;
}
}
if (count < 2 || count > 3)
throw new JsonException("Point3d must be an array of x, y, z");
return new Point3D(data[0], data[1], data[2]);
}
public override void Write(Utf8JsonWriter writer, Point3D value, JsonSerializerOptions options)
{
writer.WriteStartArray();
writer.WriteNumberValue(value.X);
writer.WriteNumberValue(value.Y);
writer.WriteNumberValue(value.Z);
writer.WriteEndArray();
}
}
}

View file

@ -0,0 +1,49 @@
/*************************************************************************
* ModernUO *
* Copyright (C) 2019-2020 - ModernUO Development Team *
* Email: hi@modernuo.com *
* File: JsonConfig.cs - Created: 2020/05/02 - Updated: 2020/05/02 *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see <http://www.gnu.org/licenses/>. *
*************************************************************************/
using System.IO;
using System.Text.Json;
namespace Server.Json
{
public static class JsonConfig
{
public static readonly JsonSerializerOptions Options = new JsonSerializerOptions
{
ReadCommentHandling = JsonCommentHandling.Skip,
WriteIndented = true,
AllowTrailingCommas = true,
};
public static T Deserialize<T>(string filePath, JsonSerializerOptions options = null)
{
if (!File.Exists(filePath)) return default;
string text = File.ReadAllText(filePath, Utility.UTF8);
return JsonSerializer.Deserialize<T>(text, options ?? Options);
}
public static void Serialize(string filePath, object value, JsonSerializerOptions options = null)
{
if (File.Exists(filePath)) File.Delete(filePath);
File.WriteAllText(filePath, JsonSerializer.Serialize(value, options ?? Options));
}
}
}

View file

@ -1,15 +0,0 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class MapConverter : JsonConverter<Map>
{
public override Map Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
=> Map.Parse(reader.GetString());
public override void Write(Utf8JsonWriter writer, Map value, JsonSerializerOptions options)
=> writer.WriteStringValue(value.Name);
}
}

View file

@ -1,47 +0,0 @@
using System;
using System.Text.Json;
using System.Text.Json.Serialization;
namespace Server.Json
{
public class Point3dConverter : JsonConverter<Point3D>
{
public override Point3D Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options)
{
if (reader.TokenType != JsonTokenType.StartArray)
throw new JsonException("Point3d must be an array of x, y, z");
var data = new int[3];
var count = 0;
while (true)
{
reader.Read();
if (reader.TokenType == JsonTokenType.EndArray)
break;
if (reader.TokenType == JsonTokenType.Number)
{
if (count < 3)
data[count] = reader.GetInt32();
count++;
}
}
if (count < 2 || count > 3)
throw new JsonException("Point3d must be an array of x, y, z");
return new Point3D(data[0], data[1], data[2]);
}
public override void Write(Utf8JsonWriter writer, Point3D value, JsonSerializerOptions options)
{
writer.WriteStartArray();
writer.WriteNumberValue(value.X);
writer.WriteNumberValue(value.Y);
writer.WriteNumberValue(value.Z);
writer.WriteEndArray();
}
}
}

View file

@ -45,8 +45,6 @@ namespace Server
private static string m_BaseDirectory;
private static string m_ExePath;
private static bool m_Cache = true;
private static bool m_Profiling;
private static DateTime m_ProfileStart;
private static TimeSpan m_ProfileTime;
@ -69,9 +67,6 @@ namespace Server
private static readonly double m_HighFrequency = 1000.0 / Stopwatch.Frequency;
private static readonly double m_LowFrequency = 1000.0 / TimeSpan.TicksPerSecond;
private static bool m_UseHRT;
public static readonly bool Is64Bit = Environment.Is64BitProcess;
internal static ConsoleEventHandler m_ConsoleEventHandler;
private static int m_CycleIndex = 1;
@ -111,8 +106,6 @@ namespace Server
}
}
public static bool Service { get; private set; }
public static bool Debug { get; private set; }
internal static bool HaltOnWarning { get; private set; }
@ -126,7 +119,7 @@ namespace Server
public static MultiTextWriter MultiConsoleOut { get; private set; }
public static bool UsingHighResolutionTiming => m_UseHRT && m_HighRes && !Unix;
public static bool UsingHighResolutionTiming => m_HighRes && !Unix;
public static long TickCount => (long)Ticks;
@ -134,7 +127,7 @@ namespace Server
{
get
{
if (m_UseHRT && m_HighRes && !Unix) return Stopwatch.GetTimestamp() * m_HighFrequency;
if (m_HighRes && !Unix) return Stopwatch.GetTimestamp() * m_HighFrequency;
return DateTime.UtcNow.Ticks * m_LowFrequency;
}
@ -188,21 +181,12 @@ namespace Server
if (Debug)
Utility.Separate(sb, "-debug", " ");
if (Service)
Utility.Separate(sb, "-service", " ");
if (m_Profiling)
Utility.Separate(sb, "-profile", " ");
if (!m_Cache)
Utility.Separate(sb, "-nocache", " ");
if (HaltOnWarning)
Utility.Separate(sb, "-haltonwarning", " ");
if (m_UseHRT)
Utility.Separate(sb, "-usehrt", " ");
return sb.ToString();
}
}
@ -216,14 +200,9 @@ namespace Server
public static string FindDataFile(string path)
{
var config = Configuration.Instance;
if (config.DataDirectories.Count == 0)
throw new InvalidOperationException(
"Attempted to FindDataFile before DataDirectories list has been filled.");
string fullPath = null;
foreach (var p in config.DataDirectories)
foreach (var p in ServerConfiguration.DataDirectories)
{
fullPath = Path.Combine(p, path);
@ -262,7 +241,7 @@ namespace Server
// ignored
}
if (!close && !Service)
if (!close)
{
try
{
@ -283,7 +262,7 @@ namespace Server
private static bool OnConsoleEvent(ConsoleEventType type)
{
if (World.Saving || (Service && type == ConsoleEventType.CTRL_LOGOFF_EVENT))
if (World.Saving || type == ConsoleEventType.CTRL_LOGOFF_EVENT)
return true;
Kill(); // Kill -> HandleClosed will handle waiting for the completion of flushing to disk
@ -338,47 +317,25 @@ namespace Server
foreach (var a in args)
if (Insensitive.Equals(a, "-debug"))
Debug = true;
else if (Insensitive.Equals(a, "-service"))
Service = true;
else if (Insensitive.Equals(a, "-profile"))
Profiling = true;
else if (Insensitive.Equals(a, "-nocache"))
m_Cache = false;
else if (Insensitive.Equals(a, "-haltonwarning"))
HaltOnWarning = true;
else if (Insensitive.Equals(a, "-usehrt"))
m_UseHRT = true;
try
{
if (Service)
{
if (!Directory.Exists("Logs"))
Directory.CreateDirectory("Logs");
Console.SetOut(MultiConsoleOut = new MultiTextWriter(new FileLogger("Logs/Console.log")));
}
else
{
Console.SetOut(MultiConsoleOut = new MultiTextWriter(Console.Out));
}
}
catch
{
// ignored
}
Thread = Thread.CurrentThread;
Process = Process.GetCurrentProcess();
Assembly = Assembly.GetEntryAssembly();
if (Assembly == null)
throw new Exception("Core: Assembly entry is missing.");
if (Thread != null)
Thread.Name = "Core Thread";
if (BaseDirectory.Length > 0)
Directory.SetCurrentDirectory(BaseDirectory);
var ver = Assembly.GetName().Version;
var ver = Assembly.GetName().Version ?? new Version();
Console.ForegroundColor = ConsoleColor.Green;
// Added to help future code support on forums, as a 'check' people can ask for to it see if they recompiled core or not
@ -389,14 +346,6 @@ namespace Server
Console.ResetColor();
Console.WriteLine();
var config = Configuration.Instance;
foreach (var dir in config.DataDirectories.Where(dir => !Directory.Exists(dir)))
{
Console.ForegroundColor = ConsoleColor.DarkYellow;
Console.WriteLine("Core: Config directory {0} does not exist.", dir);
Console.ResetColor();
}
var ttObj = new Timer.TimerThread();
timerThread = new Thread(ttObj.TimerMain)
{
@ -413,9 +362,8 @@ namespace Server
if (ProcessorCount > 1)
MultiProcessor = true;
if (MultiProcessor || Is64Bit)
Console.WriteLine("Core: Optimizing for {0} {2}processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s",
Is64Bit ? "64-bit " : "");
if (MultiProcessor)
Console.WriteLine("Core: Optimizing for {0} processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s");
if (IsWindows)
{
@ -426,13 +374,14 @@ namespace Server
if (GCSettings.IsServerGC)
Console.WriteLine("Core: Server garbage collection mode enabled");
if (m_UseHRT)
Console.WriteLine("Core: Requested high resolution timing ({0})",
UsingHighResolutionTiming ? "Supported" : "Unsupported");
Console.WriteLine("Core: High resolution timing ({0})",
UsingHighResolutionTiming ? "Supported" : "Unsupported");
Console.WriteLine("SecureRandomImpl: {0} ({1})", SecureRandomImpl.Name,
SecureRandomImpl.IsHardwareRNG ? "Hardware" : "Software");
ServerConfiguration.LoadConfiguration();
// Load Assembly Scripts.CS.dll
AssemblyHandler.LoadScripts();

View file

@ -208,7 +208,7 @@ namespace Server
for (var i = 0; i < 0x4000; ++i)
{
if (i == 1 || (i > 0 && (i & 0x1F) == 0)) bin.ReadInt32(); // header
if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header
var flags = (TileFlag)bin.ReadInt64();
bin.ReadInt16(); // skip 2 bytes -- textureID

View file

@ -130,24 +130,17 @@ namespace Server
{
Console.WriteLine("failed");
if (!Core.Service)
{
Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n)", typeName);
Console.WriteLine("Error: Type '{0}' was not found. Delete all of those types? (y/n)", typeName);
if (Console.ReadKey(true).Key == ConsoleKey.Y)
{
types.Add(null);
Console.Write("World: Loading...");
continue;
}
Console.WriteLine("Types will not be deleted. An exception will be thrown.");
}
else
if (Console.ReadKey(true).Key == ConsoleKey.Y)
{
Console.WriteLine("Error: Type '{0}' was not found.", typeName);
types.Add(null);
Console.Write("World: Loading...");
continue;
}
Console.WriteLine("Types will not be deleted. An exception will be thrown.");
throw new Exception($"Bad type '{typeName}'");
}
@ -454,46 +447,39 @@ namespace Server
Console.WriteLine(" - Type: {0}", failedType);
Console.WriteLine(" - Serial: {0}", failedSerial);
if (!Core.Service)
Console.WriteLine("Delete the object? (y/n)");
if (Console.ReadKey(true).Key == ConsoleKey.Y)
{
Console.WriteLine("Delete the object? (y/n)");
if (Console.ReadKey(true).Key == ConsoleKey.Y)
if (failedType != typeof(BaseGuild))
{
if (failedType != typeof(BaseGuild))
Console.WriteLine("Delete all objects of that type? (y/n)");
if (Console.ReadKey(true).Key == ConsoleKey.Y)
{
Console.WriteLine("Delete all objects of that type? (y/n)");
if (Console.ReadKey(true).Key == ConsoleKey.Y)
{
if (failedMobiles)
for (var i = 0; i < mobiles.Count;)
if (mobiles[i].TypeID == failedTypeID)
mobiles.RemoveAt(i);
else
++i;
else if (failedItems)
for (var i = 0; i < items.Count;)
if (items[i].TypeID == failedTypeID)
items.RemoveAt(i);
else
++i;
}
if (failedMobiles)
for (var i = 0; i < mobiles.Count;)
if (mobiles[i].TypeID == failedTypeID)
mobiles.RemoveAt(i);
else
++i;
else if (failedItems)
for (var i = 0; i < items.Count;)
if (items[i].TypeID == failedTypeID)
items.RemoveAt(i);
else
++i;
}
SaveIndex(mobiles, MobileIndexPath);
SaveIndex(items, ItemIndexPath);
SaveIndex(guilds, GuildIndexPath);
}
Console.WriteLine("After pressing return an exception will be thrown and the server will terminate.");
Console.ReadLine();
}
else
{
Console.WriteLine("An exception will be thrown and the server will terminate.");
SaveIndex(mobiles, MobileIndexPath);
SaveIndex(items, ItemIndexPath);
SaveIndex(guilds, GuildIndexPath);
}
Console.WriteLine("After pressing return an exception will be thrown and the server will terminate.");
Console.ReadLine();
throw new Exception(
$"Load failed (items={failedItems}, mobiles={failedMobiles}, guilds={failedGuilds}, type={failedType}, serial={failedSerial})",
failed);