diff --git a/Projects/Server/Configuration/ServerConfiguration.cs b/Projects/Server/Configuration/ServerConfiguration.cs index c5e91f83e..17598e163 100644 --- a/Projects/Server/Configuration/ServerConfiguration.cs +++ b/Projects/Server/Configuration/ServerConfiguration.cs @@ -15,9 +15,9 @@ using System; using System.Collections.Generic; +using System.Globalization; using System.IO; using System.Net; -using System.Text.Json.Serialization; using Server.Json; namespace Server @@ -29,43 +29,53 @@ namespace Server private static ServerSettings m_Settings; private static bool m_Mocked; - public static List DataDirectories => m_Settings.dataDirectories; + public static List DataDirectories => m_Settings.DataDirectories; - public static List Listeners => m_Settings.listeners; + public static List Listeners => m_Settings.Listeners; public static string GetSetting(string key, string defaultValue) { - m_Settings.settings.TryGetValue(key, out var value); + m_Settings.Settings.TryGetValue(key, out var value); return value ?? defaultValue; } public static int GetSetting(string key, int defaultValue) { - m_Settings.settings.TryGetValue(key, out var strValue); + m_Settings.Settings.TryGetValue(key, out var strValue); return int.TryParse(strValue, out var value) ? value : defaultValue; } public static long GetSetting(string key, long defaultValue) { - m_Settings.settings.TryGetValue(key, out var strValue); + m_Settings.Settings.TryGetValue(key, out var strValue); return long.TryParse(strValue, out var value) ? value : defaultValue; } public static bool GetSetting(string key, bool defaultValue) { - m_Settings.settings.TryGetValue(key, out var strValue); + m_Settings.Settings.TryGetValue(key, out var strValue); return bool.TryParse(strValue, out var value) ? value : defaultValue; } public static T GetSetting(string key, T defaultValue) where T : struct, Enum { - m_Settings.settings.TryGetValue(key, out var strValue); + m_Settings.Settings.TryGetValue(key, out var strValue); return Enum.TryParse(strValue, out T value) ? value : defaultValue; } + public static T? GetSetting(string key) where T : struct, Enum + { + if (!m_Settings.Settings.TryGetValue(key, out var strValue)) + { + return null; + } + + return Enum.TryParse(strValue, out T value) ? value : null; + } + public static string GetOrUpdateSetting(string key, string defaultValue) { - if (m_Settings.settings.TryGetValue(key, out var value)) + if (m_Settings.Settings.TryGetValue(key, out var value)) { return value; } @@ -78,7 +88,7 @@ namespace Server { int value; - if (m_Settings.settings.TryGetValue(key, out var strValue)) + if (m_Settings.Settings.TryGetValue(key, out var strValue)) { value = int.TryParse(strValue, out value) ? value : defaultValue; } @@ -94,7 +104,7 @@ namespace Server { long value; - if (m_Settings.settings.TryGetValue(key, out var strValue)) + if (m_Settings.Settings.TryGetValue(key, out var strValue)) { value = long.TryParse(strValue, out value) ? value : defaultValue; } @@ -110,7 +120,7 @@ namespace Server { bool value; - if (m_Settings.settings.TryGetValue(key, out var strValue)) + if (m_Settings.Settings.TryGetValue(key, out var strValue)) { value = bool.TryParse(strValue, out value) ? value : defaultValue; } @@ -126,7 +136,7 @@ namespace Server { TimeSpan value; - if (m_Settings.settings.TryGetValue(key, out var strValue)) + if (m_Settings.Settings.TryGetValue(key, out var strValue)) { value = TimeSpan.TryParse(strValue, out value) ? value : defaultValue; } @@ -142,7 +152,7 @@ namespace Server { T value; - if (m_Settings.settings.TryGetValue(key, out var strValue)) + if (m_Settings.Settings.TryGetValue(key, out var strValue)) { value = Enum.TryParse(strValue, out value) ? value : defaultValue; } @@ -156,7 +166,7 @@ namespace Server public static void SetSetting(string key, string value) { - m_Settings.settings[key] = value; + m_Settings.Settings[key] = value; Save(); } @@ -168,7 +178,7 @@ namespace Server if (File.Exists(m_FilePath)) { - Console.Write($"Core: Reading server configuration from {m_RelPath}..."); + Core.WriteConsole($"Reading server configuration from {m_RelPath}..."); m_Settings = JsonConfig.Deserialize(m_FilePath); if (m_Settings == null) @@ -194,33 +204,105 @@ namespace Server return; } - if (m_Settings.dataDirectories.Count == 0) + if (m_Settings.DataDirectories.Count == 0) { updated = true; - Utility.PushColor(ConsoleColor.DarkYellow); - Console.WriteLine("Core: Server configuration is missing data directories."); - Utility.PopColor(); - m_Settings.dataDirectories.AddRange(GetDataDirectories()); + m_Settings.DataDirectories.AddRange(GetDataDirectories()); } - if (m_Settings.listeners.Count == 0) + if (m_Settings.Listeners.Count == 0) { updated = true; - Utility.PushColor(ConsoleColor.DarkYellow); - Console.WriteLine("Core: Server is missing socket listener IP addresses."); - Utility.PopColor(); - m_Settings.listeners.AddRange(GetListeners()); + m_Settings.Listeners.AddRange(GetListeners()); + } + + if (m_Settings.Expansion == null) + { + var expansion = GetSetting("currentExpansion"); + var hasExpansion = expansion != null; + + expansion ??= GetExpansion(); + + if (expansion <= Expansion.ML && !hasExpansion) + { + SetPre6000Support(); + } + + updated = true; + m_Settings.Expansion = expansion; } if (updated) { Save(); Utility.PushColor(ConsoleColor.Green); - Console.WriteLine($"Core: Server configuration saved to {m_RelPath}."); + Core.WriteConsoleLine($"Server configuration saved to {m_RelPath}."); Utility.PopColor(); } } + private static void SetPre6000Support() + { + Console.WriteLine("Will you be using a client version older than 6.0.0.0?"); + + do + { + Console.Write("y or [n]> "); + var input = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(input) || input.InsensitiveStartsWith("n")) + { + return; + } + + if (input.InsensitiveStartsWith("y")) + { + SetSetting("maps.enablePre6000Trammel", true.ToString()); + SetSetting("maps.enableMapDiffPatches", true.ToString()); + return; + } + + Core.WriteConsoleLine($"Invalid option. ({input})"); + } while (true); + } + + private static Expansion GetExpansion() + { + Console.WriteLine("Please choose an expansion by typing the number or short name:"); + var expansions = ExpansionInfo.Table; + + for (int i = 0; i < expansions.Length; i++) + { + var info = expansions[i]; + Console.WriteLine(" - {0,2}: {1} ({2})", i, ((Expansion)info.ID).ToString(), info.Name); + } + + var maxExpansion = (Expansion)expansions[^1].ID; + var maxExpansionName = maxExpansion.ToString(); + + do + { + Console.Write("[{0}]> ", maxExpansionName); + var input = Console.ReadLine(); + if (string.IsNullOrWhiteSpace(input)) + { + return maxExpansion; + } + + if (int.TryParse(input, NumberStyles.Integer, null, out var number) && number >= 0 && + number < expansions.Length) + { + return (Expansion)number; + } + + if (Enum.TryParse(input, out var expansion)) + { + return expansion; + } + + Core.WriteConsoleLine($"Invalid expansion. ({input})"); + } while (true); + } + private static List GetDataDirectories() { Console.WriteLine("Please enter the absolute path to the Ultima Online data:"); @@ -239,11 +321,11 @@ namespace Server if (Directory.Exists(directory)) { directories.Add(directory); - Console.WriteLine("Core: Path {0} added.", directory); + Core.WriteConsoleLine($"Path {directory} added."); } else { - Console.WriteLine("Core: Path does not exist. ({0})"); + Core.WriteConsoleLine($"Path does not exist. ({directory})"); } } while (true); @@ -276,11 +358,11 @@ namespace Server if (IPEndPoint.TryParse(ipStr, out var ip)) { ips.Add(ip); - Console.WriteLine("Core: {0} added.", ipStr); + Core.WriteConsoleLine($"Core: {ipStr} added."); } else { - Console.WriteLine("Core: {0} is not a valid IP or port"); + Core.WriteConsoleLine($"{ipStr} is not a valid IP or port"); } } while (true); @@ -301,17 +383,5 @@ namespace Server JsonConfig.Serialize(m_FilePath, m_Settings); } - - internal class ServerSettings - { - [JsonPropertyName("dataDirectories")] - public List dataDirectories { get; set; } = new(); - - [JsonPropertyName("listeners")] - public List listeners { get; set; } = new(); - - [JsonPropertyName("settings")] - public SortedDictionary settings { get; set; } = new(); - } } } diff --git a/Projects/Server/Configuration/ServerSettings.cs b/Projects/Server/Configuration/ServerSettings.cs new file mode 100644 index 000000000..a9c9178be --- /dev/null +++ b/Projects/Server/Configuration/ServerSettings.cs @@ -0,0 +1,36 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ServerSettings.cs * + * * + * 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. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System.Collections.Generic; +using System.Net; +using System.Text.Json.Serialization; + +namespace Server +{ + public class ServerSettings + { + [JsonPropertyName("dataDirectories")] + public List DataDirectories { get; set; } = new(); + + [JsonPropertyName("listeners")] + public List Listeners { get; set; } = new(); + + [JsonPropertyName("expansion")] + public Expansion? Expansion { get; set; } + + [JsonPropertyName("settings")] + public SortedDictionary Settings { get; set; } = new(); + } +} diff --git a/Projects/Server/IAccount.cs b/Projects/Server/IAccount.cs index 2efd50439..e141289a1 100644 --- a/Projects/Server/IAccount.cs +++ b/Projects/Server/IAccount.cs @@ -4,7 +4,7 @@ namespace Server.Accounting { public static class AccountGold { - public static bool Enabled = false; + public static bool Enabled { get; private set; } /// /// This amount specifies the value at which point Gold turns to Platinum. @@ -20,13 +20,20 @@ namespace Server.Accounting /// Enables or Disables automatic conversion of Gold and Checks to Bank Currency /// when they are added to a bank box container. /// - public static bool ConvertOnBank = true; + public static bool ConvertOnBank { get; private set; } /// /// Enables or Disables automatic conversion of Gold and Checks to Bank Currency /// when they are added to a secure trade container. /// - public static bool ConvertOnTrade = false; + public static bool ConvertOnTrade { get; private set; } + + public static void Configure() + { + Enabled = ServerConfiguration.GetSetting("accountGold.enable", Core.TOL); + ConvertOnBank = ServerConfiguration.GetSetting("accountGold.convertOnBank", true); + ConvertOnTrade = ServerConfiguration.GetSetting("accountGold.convertOnTrade", false); + } } public interface IGoldAccount diff --git a/Projects/Server/Items/VirtualCheck.cs b/Projects/Server/Items/VirtualCheck.cs index 0710d8c02..c079663ae 100644 --- a/Projects/Server/Items/VirtualCheck.cs +++ b/Projects/Server/Items/VirtualCheck.cs @@ -20,8 +20,12 @@ namespace Server.Items { public sealed class VirtualCheck : Item { - // TODO: Move to configuration - public static bool UseEditGump = false; + public static bool UseEditGump { get; private set; } + + public static void Configure() + { + UseEditGump = ServerConfiguration.GetSetting("virtualChecks.useEditGump", true); + } private int m_Gold; diff --git a/Projects/Server/Json/Converters/JsonNullableEnumConverter.cs b/Projects/Server/Json/Converters/JsonNullableEnumConverter.cs new file mode 100644 index 000000000..599866e1b --- /dev/null +++ b/Projects/Server/Json/Converters/JsonNullableEnumConverter.cs @@ -0,0 +1,51 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: JsonNullableEnumConverter.cs * + * * + * 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. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Server.Json.Converters +{ + class JsonNullableEnumConverter : JsonConverter where T : struct, Enum + { + private readonly JsonConverter _converter; + + public JsonNullableEnumConverter(JsonConverter converter) => _converter = converter; + + public override T? Read(ref Utf8JsonReader reader, Type typeToConvert, JsonSerializerOptions options) + { + if (reader.TokenType == JsonTokenType.Null) + { + reader.Read(); + return null; + } + + return _converter.Read(ref reader, typeof(T), options); + } + + public override void Write(Utf8JsonWriter writer, T? value, JsonSerializerOptions options) + { + if (value == null) + { + writer.WriteNullValue(); + } + else + { + _converter.Write(writer, value.Value, options); + } + } + } +} diff --git a/Projects/Server/Json/Converters/JsonNullableEnumConverterFactory.cs b/Projects/Server/Json/Converters/JsonNullableEnumConverterFactory.cs new file mode 100644 index 000000000..73c0f532e --- /dev/null +++ b/Projects/Server/Json/Converters/JsonNullableEnumConverterFactory.cs @@ -0,0 +1,38 @@ +/************************************************************************* + * ModernUO * + * Copyright 2019-2021 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: JsonNullableEnumConverterFactory.cs * + * * + * 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. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Text.Json; +using System.Text.Json.Serialization; + +namespace Server.Json.Converters +{ + public class JsonNullableEnumConverterFactory : JsonConverterFactory + { + private readonly JsonStringEnumConverter _stringEnumConverter; + + public JsonNullableEnumConverterFactory(JsonNamingPolicy? namingPolicy = null, bool allowIntegerValues = true) => + _stringEnumConverter = new JsonStringEnumConverter(namingPolicy, allowIntegerValues); + + public override bool CanConvert(Type typeToConvert) => Nullable.GetUnderlyingType(typeToConvert)?.IsEnum == true; + + public override JsonConverter? CreateConverter(Type typeToConvert, JsonSerializerOptions options) + { + var type = Nullable.GetUnderlyingType(typeToConvert); + return (JsonConverter?)Activator.CreateInstance(typeof(JsonNullableEnumConverter<>).MakeGenericType(type!), + _stringEnumConverter.CreateConverter(type, options)); + } + } +} diff --git a/Projects/Server/Json/JsonConfig.cs b/Projects/Server/Json/JsonConfig.cs index 7e2df04d1..f14a534ba 100644 --- a/Projects/Server/Json/JsonConfig.cs +++ b/Projects/Server/Json/JsonConfig.cs @@ -19,6 +19,7 @@ using System.IO; using System.Text.Encodings.Web; using System.Text.Json; using System.Text.Json.Serialization; +using Server.Json.Converters; using Server.Text; namespace Server.Json @@ -39,6 +40,7 @@ namespace Server.Json Encoder = JavaScriptEncoder.UnsafeRelaxedJsonEscaping }; + options.Converters.Add(new JsonNullableEnumConverterFactory()); options.Converters.Add(new JsonStringEnumConverter()); options.Converters.Add(new MapConverterFactory()); options.Converters.Add(new Point3DConverterFactory()); diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index 8aadda4c9..b61dad707 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -297,7 +297,7 @@ namespace Server _ => "CTRL+C" }; - Console.WriteLine("Core: Detected {0} pressed.", keypress); + WriteConsoleLine($"Detected {keypress} pressed."); e.Cancel = true; Kill(); } @@ -410,7 +410,7 @@ namespace Server ".TrimMultiline()); Utility.PopColor(); - Console.WriteLine("Core: Running on {0}", RuntimeInformation.FrameworkDescription); + WriteConsoleLine($"Running on {RuntimeInformation.FrameworkDescription}"); var ttObj = new Timer.TimerThread(); _timerThread = new Thread(ttObj.TimerMain) @@ -422,7 +422,7 @@ namespace Server if (s.Length > 0) { - Console.WriteLine("Core: Running with arguments: {0}", s); + WriteConsoleLine($"Running with arguments: {s}"); } ProcessorCount = Environment.ProcessorCount; @@ -434,20 +434,17 @@ namespace Server if (MultiProcessor) { - Console.WriteLine("Core: Optimizing for {0} processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s"); + WriteConsoleLine($"Optimizing for {ProcessorCount} processor{(ProcessorCount == 1 ? "" : "s")}"); } Console.CancelKeyPress += Console_CancelKeyPressed; if (GCSettings.IsServerGC) { - Console.WriteLine("Core: Server garbage collection mode enabled"); + WriteConsoleLine(": Server garbage collection mode enabled"); } - Console.WriteLine( - "Core: High resolution timing ({0})", - Stopwatch.IsHighResolution ? "Supported" : "Unsupported" - ); + WriteConsoleLine($"High resolution timing ({(Stopwatch.IsHighResolution ? "Supported" : "Unsupported")})"); ServerConfiguration.Load(); @@ -469,7 +466,6 @@ namespace Server VerifySerialization(); - MapLoader.LoadMaps(); AssemblyHandler.Invoke("Configure"); TileMatrixLoader.LoadTileMatrix(); @@ -609,5 +605,17 @@ namespace Server Parallel.ForEach(assembly.GetTypes(), VerifyType); } } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteConsole(string message) + { + Console.Write("Core: {0}", message); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal static void WriteConsoleLine(string message) + { + Console.WriteLine("Core: {0}", message); + } } } diff --git a/Projects/Server/Maps/MapLoader.cs b/Projects/Server/Maps/MapLoader.cs index 2fb146daf..5e3ab0667 100644 --- a/Projects/Server/Maps/MapLoader.cs +++ b/Projects/Server/Maps/MapLoader.cs @@ -23,7 +23,7 @@ using Server.Json; namespace Server { - internal static class MapLoader + public static class MapLoader { /* Here we configure all maps. Some notes: * @@ -32,7 +32,7 @@ namespace Server * 3) Map 255 is reserved for core use. * 4) Changing or removing any predefined maps may cause server instability. * - * Map definitions are modified in Data/map-definitions.json: + * Map definitions are modified in Data/Map Definitions/.json: * - : An unreserved unique index for this map * - : An identification number used in client communications. For any visible maps, this value must be from 0-5 * - : A file identification number. For any visible maps, this value must be from 0-5 @@ -41,8 +41,12 @@ namespace Server * - : Reference name for the map, used in props gump, get/set commands, region loading, etc * - : Rules and restrictions associated with the map. See documentation for details */ - internal static void LoadMaps() + [CallPriority(2)] + public static void Configure() { + // Set to true to support < 6.0.0 clients where map0.mul is both Felucca & Trammel + var pre6000Trammel = ServerConfiguration.GetOrUpdateSetting("maps.enablePre6000Trammel", false); + var failures = new List(); var count = 0; @@ -59,6 +63,12 @@ namespace Server foreach (var def in maps) { + if (def.Id == 1 && pre6000Trammel) + { + // Use Old Haven by changing file index to Felucca + def.FileIndex = 0; + } + try { RegisterMap(def); diff --git a/Projects/Server/Network/Packets/OutgoingGumpPackets.cs b/Projects/Server/Network/Packets/OutgoingGumpPackets.cs index c693a41b9..12052e35c 100644 --- a/Projects/Server/Network/Packets/OutgoingGumpPackets.cs +++ b/Projects/Server/Network/Packets/OutgoingGumpPackets.cs @@ -74,7 +74,7 @@ namespace Server.Network if (error != ZlibError.Okay) { Utility.PushColor(ConsoleColor.Red); - Console.WriteLine("Core: Gump compression failed {0}", error); + Core.WriteConsoleLine($"Gump compression failed {error}"); Utility.PopColor(); writer.Write(4); diff --git a/Projects/Server/World/World.cs b/Projects/Server/World/World.cs index bc3bb857c..164d8fc3f 100644 --- a/Projects/Server/World/World.cs +++ b/Projects/Server/World/World.cs @@ -657,12 +657,14 @@ namespace Server [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void RemoveGuild(BaseGuild guild) => Guilds.Remove(guild.Serial); + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteConsole(string message) { var now = DateTime.UtcNow; Console.Write("[{0} {1}] World: {2}", now.ToShortDateString(), now.ToLongTimeString(), message); } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static void WriteConsoleLine(string message) { var now = DateTime.UtcNow; diff --git a/Projects/UOContent.Tests/Tests/Items/Books/BookPacketTests.cs b/Projects/UOContent.Tests/Tests/Items/Books/BookPacketTests.cs index d236533be..c5662f9fe 100644 --- a/Projects/UOContent.Tests/Tests/Items/Books/BookPacketTests.cs +++ b/Projects/UOContent.Tests/Tests/Items/Books/BookPacketTests.cs @@ -8,6 +8,31 @@ using Xunit; namespace UOContent.Tests { + public class TestBook : BaseBook + { + public TestBook(int itemID, int pageCount = 20, bool writable = true) : base(itemID, pageCount, writable) + { + } + + public TestBook(int itemID, string title, string author, int pageCount, bool writable) : base(itemID, title, author, pageCount, writable) + { + } + + public TestBook(int itemID, bool writable) : base(itemID, writable) + { + } + + public TestBook(Serial serial) : base(serial) + { + Pages = new BookPageInfo[20]; + + for (var i = 0; i < Pages.Length; ++i) + { + Pages[i] = new BookPageInfo(); + } + } + } + public class BookPacketTests : IClassFixture { [Theory] @@ -17,7 +42,8 @@ namespace UOContent.Tests var m = new Mobile(0x1); m.DefaultMobileInit(); - var book = new BlueBook { Author = author, Title = title }; + Serial serial = 0x1001; + var book = new TestBook(serial) { Author = author, Title = title }; var expected = new BookHeader(m, book).Compile(); @@ -34,7 +60,8 @@ namespace UOContent.Tests var m = new Mobile(0x1); m.DefaultMobileInit(); - var book = new BlueBook { Author = "Some Author", Title = "Some Title" }; + Serial serial = 0x1001; + var book = new TestBook(serial) { Author = "Some Author", Title = "Some Title" }; book.Pages[0].Lines = new[] { "Some books start with actual content", diff --git a/Projects/UOContent/Configuration/ExpansionConfiguration.cs b/Projects/UOContent/Configuration/ExpansionConfiguration.cs index 67bc17cf5..ada2e3282 100644 --- a/Projects/UOContent/Configuration/ExpansionConfiguration.cs +++ b/Projects/UOContent/Configuration/ExpansionConfiguration.cs @@ -1,5 +1,3 @@ -using Server.Accounting; -using Server.Items; using Server.Network; namespace Server @@ -8,13 +6,6 @@ namespace Server { public static void Configure() { - Core.Expansion = ServerConfiguration.GetOrUpdateSetting("currentExpansion", Expansion.TOL); - - AccountGold.Enabled = ServerConfiguration.GetSetting("accountGold.enable", Core.TOL); - AccountGold.ConvertOnBank = ServerConfiguration.GetSetting("accountGold.convertOnBank", true); - AccountGold.ConvertOnTrade = ServerConfiguration.GetSetting("accountGold.convertOnTrade", false); - VirtualCheck.UseEditGump = ServerConfiguration.GetSetting("virtualChecks.useEditGump", true); - Mobile.InsuranceEnabled = ServerConfiguration.GetSetting("insurance.enable", Core.AOS); ObjectPropertyList.Enabled = ServerConfiguration.GetSetting("opl.enable", Core.AOS); var visibleDamage = ServerConfiguration.GetSetting("visibleDamage", Core.AOS); @@ -30,8 +21,8 @@ namespace Server if (ObjectPropertyList.Enabled) { - IncomingEntityPackets.SingleClickProps = - true; // single click for everything is overridden to check object property list + // single click for everything is overridden to check object property list + IncomingEntityPackets.SingleClickProps = true; } Mobile.AOSStatusHandler = AOS.GetStatus; diff --git a/Projects/UOContent/Items/Books/BaseBook.cs b/Projects/UOContent/Items/Books/BaseBook.cs index ce885f369..f579c180c 100644 --- a/Projects/UOContent/Items/Books/BaseBook.cs +++ b/Projects/UOContent/Items/Books/BaseBook.cs @@ -78,7 +78,7 @@ namespace Server.Items [CommandProperty(AccessLevel.GameMaster)] public int PagesCount => Pages.Length; - public BookPageInfo[] Pages { get; private set; } + public BookPageInfo[] Pages { get; protected set; } public virtual BookContent DefaultContent => null; @@ -230,14 +230,7 @@ namespace Server.Items } else { - if (content != null) - { - Pages = content.Copy(); - } - else - { - Pages = Array.Empty(); - } + Pages = content?.Copy() ?? Array.Empty(); } break; @@ -262,14 +255,7 @@ namespace Server.Items { var content = DefaultContent; - if (content != null) - { - Pages = content.Copy(); - } - else - { - Pages = Array.Empty(); - } + Pages = content?.Copy() ?? Array.Empty(); } break;