From a264f2a34ebf1111a77c6a83ba147720912e8c5d Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 26 Dec 2021 00:43:04 -0800 Subject: [PATCH 01/19] readme: Fixes Fedora on README (#894) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1ee0cb293..87a102ff7 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ ModernUO [![Discord](https://img.shields.io/discord/751317910504603701?logo=disc [![Debian 10/11](https://img.shields.io/badge/-bullseye-A81D33?logo=debian)](https://www.debian.org/distrib/) [![Ubuntu 16/18/20 LTS](https://img.shields.io/badge/-20LTS-E95420?logo=ubuntu&logoColor=white)](https://ubuntu.com/download/server) [![CentOS 7/8](https://img.shields.io/badge/-8.5-262577?logo=centos&logoColor=white)](https://www.centos.org/download/) -[![Fedora 32/33/34](https://img.shields.io/badge/-34-0B57A4?logo=fedora&logoColor=white)](https://getfedora.org/en/server/download/) +[![Fedora 32/33/34](https://img.shields.io/badge/-fedora%2034-0B57A4)](https://getfedora.org/en/server/download/) [![RedHat 7/8](https://img.shields.io/badge/-8-BE0000?logo=red%20hat&logoColor=white)](https://access.redhat.com/downloads) #### Running the server From 58190674f9970944d6c15030a5d047de9519d114 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Dec 2021 01:27:15 -0800 Subject: [PATCH 02/19] feat: Adds StaffAccess and ResetStaffDress commands (#895) --- Projects/Server/Commands.cs | 85 ++------------- Projects/UOContent/Commands/Batch.cs | 3 +- Projects/UOContent/Commands/DragEffects.cs | 3 +- Projects/UOContent/Commands/Dupe.cs | 6 +- Projects/UOContent/Commands/Handlers.cs | 60 ++++++----- Projects/UOContent/Commands/HelpInfo.cs | 5 +- .../Commands/Object Creation/AddGump.cs | 5 +- .../Commands/Object Creation/Decorate.cs | 3 +- .../Commands/Object Creation/DecorateMag.cs | 3 +- .../Commands/Object Creation/GenTeleporter.cs | 6 +- Projects/UOContent/Commands/Profiling.cs | 12 ++- .../UOContent/Commands/ResetStaffDress.cs | 69 ++++++++++++ Projects/UOContent/Commands/ShardTime.cs | 3 +- Projects/UOContent/Commands/SignParser.cs | 3 +- Projects/UOContent/Commands/Skills.cs | 9 +- Projects/UOContent/Commands/SkillsMenu.cs | 3 +- Projects/UOContent/Commands/StaffAccess.cs | 101 ++++++++++++++++++ Projects/UOContent/Commands/Statics.cs | 18 ++-- Projects/UOContent/Commands/VisibilityList.cs | 11 +- Projects/UOContent/Commands/Wipe.cs | 12 ++- 20 files changed, 282 insertions(+), 138 deletions(-) create mode 100644 Projects/UOContent/Commands/ResetStaffDress.cs create mode 100644 Projects/UOContent/Commands/StaffAccess.cs diff --git a/Projects/Server/Commands.cs b/Projects/Server/Commands.cs index 503b24814..6c5de7deb 100644 --- a/Projects/Server/Commands.cs +++ b/Projects/Server/Commands.cs @@ -26,65 +26,20 @@ namespace Server public int Length => Arguments.Length; - public string GetString(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return ""; - } + public string GetString(int index) => index < 0 || index >= Arguments.Length ? "" : Arguments[index]; - return Arguments[index]; - } + public int GetInt32(int index) => index < 0 || index >= Arguments.Length ? 0 : Utility.ToInt32(Arguments[index]); - public int GetInt32(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return 0; - } + public uint GetUInt32(int index) => + index < 0 || index >= Arguments.Length ? 0 : Utility.ToUInt32(Arguments[index]); - return Utility.ToInt32(Arguments[index]); - } + public bool GetBoolean(int index) => index >= 0 && index < Arguments.Length && Utility.ToBoolean(Arguments[index]); - public uint GetUInt32(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return 0; - } + public double GetDouble(int index) => + index < 0 || index >= Arguments.Length ? 0.0 : Utility.ToDouble(Arguments[index]); - return Utility.ToUInt32(Arguments[index]); - } - - public bool GetBoolean(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return false; - } - - return Utility.ToBoolean(Arguments[index]); - } - - public double GetDouble(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return 0.0; - } - - return Utility.ToDouble(Arguments[index]); - } - - public TimeSpan GetTimeSpan(int index) - { - if (index < 0 || index >= Arguments.Length) - { - return TimeSpan.Zero; - } - - return Utility.ToTimeSpan(Arguments[index]); - } + public TimeSpan GetTimeSpan(int index) => + index < 0 || index >= Arguments.Length ? TimeSpan.Zero : Utility.ToTimeSpan(Arguments[index]); } public static partial class EventSink @@ -137,27 +92,7 @@ namespace Server } } - public record CommandInfo - { - public CommandInfo(AccessLevel accessLevel, string name, string[] aliases, string usage, string description) - { - AccessLevel = accessLevel; - Name = name; - Aliases = aliases; - Usage = usage; - Description = description; - } - - public AccessLevel AccessLevel { get; } - - public string Name { get; } - - public string[] Aliases { get; } - - public string Usage { get; } - - public string Description { get; } - } + public record CommandInfo(AccessLevel AccessLevel, string Name, string[] Aliases, string Usage, string Description); public class CommandInfoSorter : IComparer { diff --git a/Projects/UOContent/Commands/Batch.cs b/Projects/UOContent/Commands/Batch.cs index 84aeca315..8e7ce6b73 100644 --- a/Projects/UOContent/Commands/Batch.cs +++ b/Projects/UOContent/Commands/Batch.cs @@ -177,7 +177,8 @@ namespace Server.Commands CommandSystem.Register("Batch", AccessLevel.Counselor, Batch_OnCommand); } - [Usage("Batch"), Description("Allows multiple commands to be run at the same time.")] + [Usage("Batch")] + [Description("Allows multiple commands to be run at the same time.")] public static void Batch_OnCommand(CommandEventArgs e) { e.Mobile.SendGump(new BatchGump(e.Mobile, new Batch())); diff --git a/Projects/UOContent/Commands/DragEffects.cs b/Projects/UOContent/Commands/DragEffects.cs index d9ef33a38..d67d0d393 100644 --- a/Projects/UOContent/Commands/DragEffects.cs +++ b/Projects/UOContent/Commands/DragEffects.cs @@ -7,7 +7,8 @@ namespace Server.Commands CommandSystem.Register("DragEffects", AccessLevel.Developer, DragEffects_OnCommand); } - [Usage("DragEffects [enable=false]"), Description("Enables or disables the item drag and drop effects.")] + [Usage("DragEffects [enable=false]")] + [Description("Enables or disables the item drag and drop effects.")] public static void DragEffects_OnCommand(CommandEventArgs e) { if (e.Length == 0) diff --git a/Projects/UOContent/Commands/Dupe.cs b/Projects/UOContent/Commands/Dupe.cs index db7bfdbde..3cbf9de10 100644 --- a/Projects/UOContent/Commands/Dupe.cs +++ b/Projects/UOContent/Commands/Dupe.cs @@ -13,7 +13,8 @@ namespace Server.Commands CommandSystem.Register("DupeInBag", AccessLevel.GameMaster, DupeInBag_OnCommand); } - [Usage("Dupe [amount]"), Description("Dupes a targeted item.")] + [Usage("Dupe [amount]")] + [Description("Dupes a targeted item.")] private static void Dupe_OnCommand(CommandEventArgs e) { var amount = 1; @@ -26,7 +27,8 @@ namespace Server.Commands e.Mobile.SendMessage("What do you wish to dupe?"); } - [Usage("DupeInBag "), Description("Dupes an item at it's current location (count) number of times.")] + [Usage("DupeInBag ")] + [Description("Dupes an item at it's current location (count) number of times.")] private static void DupeInBag_OnCommand(CommandEventArgs e) { var amount = 1; diff --git a/Projects/UOContent/Commands/Handlers.cs b/Projects/UOContent/Commands/Handlers.cs index 98279f8ed..811bacff9 100644 --- a/Projects/UOContent/Commands/Handlers.cs +++ b/Projects/UOContent/Commands/Handlers.cs @@ -73,7 +73,8 @@ namespace Server.Commands CommandSystem.Register(command, access, handler); } - [Usage("SpeedBoost [true|false]"), Description("Enables a speed boost for the invoker. Disable with parameters.")] + [Usage("SpeedBoost [true|false]")] + [Description("Enables a speed boost for the invoker. Disable with parameters.")] private static void SpeedBoost_OnCommand(CommandEventArgs e) { var from = e.Mobile; @@ -97,7 +98,8 @@ namespace Server.Commands } } - [Usage("Where"), Description("Tells the commanding player his coordinates, region, and facet.")] + [Usage("Where")] + [Description("Tells the commanding player his coordinates, region, and facet.")] public static void Where_OnCommand(CommandEventArgs e) { var from = e.Mobile; @@ -127,9 +129,8 @@ namespace Server.Commands } } - [Usage("DropHolding"), Description( - "Drops the item, if any, that a targeted player is holding. The item is placed into their backpack, or if that's full, at their feet." - )] + [Usage("DropHolding")] + [Description("Drops the item, if any, that a targeted player is holding. The item is placed into their backpack, or if that's full, at their feet.")] public static void DropHolding_OnCommand(CommandEventArgs e) { e.Mobile.BeginTarget(-1, false, TargetFlags.None, DropHolding_OnTarget); @@ -274,7 +275,8 @@ namespace Server.Commands } } - [Usage("GetFollowers"), Description("Teleports all pets of a targeted player to your location.")] + [Usage("GetFollowers")] + [Description("Teleports all pets of a targeted player to your location.")] public static void GetFollowers_OnCommand(CommandEventArgs e) { e.Mobile.BeginTarget(-1, false, TargetFlags.None, GetFollowers_OnTarget); @@ -374,9 +376,8 @@ namespace Server.Commands e.Mobile.Target = new ViewEqTarget(); } - [Usage("Sound [toAll=true]"), Description( - "Plays a sound to players within 12 tiles of you. The (toAll) argument specifies to everyone, or just those who can see you." - )] + [Usage("Sound [toAll=true]")] + [Description("Plays a sound to players within 12 tiles of you. The (toAll) argument specifies to everyone, or just those who can see you.")] public static void Sound_OnCommand(CommandEventArgs e) { if (e.Length == 1) @@ -423,7 +424,8 @@ namespace Server.Commands } } - [Usage("Echo "), Description("Relays (text) as a system message.")] + [Usage("Echo ")] + [Description("Relays (text) as a system message.")] public static void Echo_OnCommand(CommandEventArgs e) { var toEcho = e.ArgString.Trim(); @@ -438,19 +440,22 @@ namespace Server.Commands } } - [Usage("Bank"), Description("Opens the bank box of a given target.")] + [Usage("Bank")] + [Description("Opens the bank box of a given target.")] public static void Bank_OnCommand(CommandEventArgs e) { e.Mobile.Target = new BankTarget(); } - [Usage("Client"), Description("Opens the client gump menu for a given player.")] + [Usage("Client")] + [Description("Opens the client gump menu for a given player.")] private static void Client_OnCommand(CommandEventArgs e) { e.Mobile.Target = new ClientTarget(); } - [Usage("Move"), Description("Repositions a targeted item or mobile.")] + [Usage("Move")] + [Description("Repositions a targeted item or mobile.")] private static void Move_OnCommand(CommandEventArgs e) { e.Mobile.Target = new PickMoveTarget(); @@ -473,9 +478,8 @@ namespace Server.Commands return validMap; } - [Usage("Go [name | serial | (x y [z]) | (deg min (N | S) deg min (E | W))]"), Description( - "With no arguments, this command brings up the go menu. With one argument, (name), you are moved to that regions \"go location.\" Or, if a numerical value is specified for one argument, (serial), you are moved to that object. Two or three arguments, (x y [z]), will move your character to that location. When six arguments are specified, (deg min (N | S) deg min (E | W)), your character will go to an approximate of those sextant coordinates." - )] + [Usage("Go [name | serial | (x y [z]) | (deg min (N | S) deg min (E | W))]")] + [Description("With no arguments, this command brings up the go menu. With one argument, (name), you are moved to that regions \"go location.\" Or, if a numerical value is specified for one argument, (serial), you are moved to that object. Two or three arguments, (x y [z]), will move your character to that location. When six arguments are specified, (deg min (N | S) deg min (E | W)), your character will go to an approximate of those sextant coordinates.")] private static void Go_OnCommand(CommandEventArgs e) { var from = e.Mobile; @@ -685,7 +689,8 @@ namespace Server.Commands } } - [Usage("Help"), Description("Lists all available commands.")] + [Usage("Help")] + [Description("Lists all available commands.")] public static void Help_OnCommand(CommandEventArgs e) { var m = e.Mobile; @@ -732,13 +737,15 @@ namespace Server.Commands } } - [Usage("SMsg "), Aliases("S", "SM"), Description("Broadcasts a message to all online staff.")] + [Usage("SMsg "), Aliases("S", "SM")] + [Description("Broadcasts a message to all online staff.")] public static void StaffMessage_OnCommand(CommandEventArgs e) { BroadcastMessage(AccessLevel.Counselor, e.Mobile.SpeechHue, $"[{e.Mobile.Name}] {e.ArgString}"); } - [Usage("BCast "), Aliases("B", "BC"), Description("Broadcasts a message to everyone online.")] + [Usage("BCast "), Aliases("B", "BC")] + [Description("Broadcasts a message to everyone online.")] public static void BroadcastMessage_OnCommand(CommandEventArgs e) { BroadcastMessage(AccessLevel.Player, 0x482, $"Staff message from {e.Mobile.Name}:"); @@ -758,7 +765,8 @@ namespace Server.Commands } } - [Usage("AutoPageNotify"), Aliases("APN"), Description("Toggles your auto-page-notify status.")] + [Usage("AutoPageNotify"), Aliases("APN")] + [Description("Toggles your auto-page-notify status.")] public static void APN_OnCommand(CommandEventArgs e) { var m = e.Mobile; @@ -789,7 +797,8 @@ namespace Server.Commands } } - [Usage("Cast "), Description("Casts a spell by name.")] + [Usage("Cast ")] + [Description("Casts a spell by name.")] public static void Cast_OnCommand(CommandEventArgs e) { if (e.Length == 1) @@ -816,19 +825,22 @@ namespace Server.Commands } } - [Usage("Stuck"), Description("Opens a menu of towns, used for teleporting stuck mobiles.")] + [Usage("Stuck")] + [Description("Opens a menu of towns, used for teleporting stuck mobiles.")] public static void Stuck_OnCommand(CommandEventArgs e) { e.Mobile.Target = new StuckMenuTarget(); } - [Usage("Light "), Description("Set your local lightlevel.")] + [Usage("Light ")] + [Description("Set your local lightlevel.")] public static void Light_OnCommand(CommandEventArgs e) { e.Mobile.LightLevel = e.GetInt32(0); } - [Usage("Stats"), Description("View some stats about the server.")] + [Usage("Stats")] + [Description("View some stats about the server.")] public static void Stats_OnCommand(CommandEventArgs e) { e.Mobile.SendMessage("Open Connections: {0}", TcpServer.Instances.Count); diff --git a/Projects/UOContent/Commands/HelpInfo.cs b/Projects/UOContent/Commands/HelpInfo.cs index b85ca8b05..3056a75cd 100644 --- a/Projects/UOContent/Commands/HelpInfo.cs +++ b/Projects/UOContent/Commands/HelpInfo.cs @@ -19,9 +19,8 @@ namespace Server.Commands FillTable(); } - [Usage("HelpInfo []"), Description( - "Gives information on a specified command, or when no argument specified, displays a gump containing all commands" - )] + [Usage("HelpInfo []")] + [Description("Gives information on a specified command, or when no argument specified, displays a gump containing all commands")] private static void HelpInfo_OnCommand(CommandEventArgs e) { if (e.Length > 0) diff --git a/Projects/UOContent/Commands/Object Creation/AddGump.cs b/Projects/UOContent/Commands/Object Creation/AddGump.cs index 84e3523a4..bf7890052 100644 --- a/Projects/UOContent/Commands/Object Creation/AddGump.cs +++ b/Projects/UOContent/Commands/Object Creation/AddGump.cs @@ -92,9 +92,8 @@ namespace Server.Gumps CommandSystem.Register("AddMenu", AccessLevel.GameMaster, AddMenu_OnCommand); } - [Usage("AddMenu [searchString]"), Description( - "Opens an add menu, with an optional initial search string. This menu allows you to search for Items or Mobiles and add them interactively." - )] + [Usage("AddMenu [searchString]")] + [Description("Opens an add menu, with an optional initial search string. This menu allows you to search for Items or Mobiles and add them interactively.")] private static void AddMenu_OnCommand(CommandEventArgs e) { var val = e.ArgString.Trim(); diff --git a/Projects/UOContent/Commands/Object Creation/Decorate.cs b/Projects/UOContent/Commands/Object Creation/Decorate.cs index f8a14b4f2..e36944c44 100644 --- a/Projects/UOContent/Commands/Object Creation/Decorate.cs +++ b/Projects/UOContent/Commands/Object Creation/Decorate.cs @@ -20,7 +20,8 @@ namespace Server.Commands CommandSystem.Register("Decorate", AccessLevel.Administrator, Decorate_OnCommand); } - [Usage("Decorate"), Description("Generates world decoration.")] + [Usage("Decorate")] + [Description("Generates world decoration.")] private static void Decorate_OnCommand(CommandEventArgs e) { m_Mobile = e.Mobile; diff --git a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs index fdea8e992..be9d86629 100644 --- a/Projects/UOContent/Commands/Object Creation/DecorateMag.cs +++ b/Projects/UOContent/Commands/Object Creation/DecorateMag.cs @@ -20,7 +20,8 @@ namespace Server.Commands CommandSystem.Register("DecorateMag", AccessLevel.Administrator, DecorateMag_OnCommand); } - [Usage("DecorateMag"), Description("Generates world decoration.")] + [Usage("DecorateMag")] + [Description("Generates world decoration.")] private static void DecorateMag_OnCommand(CommandEventArgs e) { m_Mobile = e.Mobile; diff --git a/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs b/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs index daa84d9b0..b597611d4 100644 --- a/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs +++ b/Projects/UOContent/Commands/Object Creation/GenTeleporter.cs @@ -33,7 +33,8 @@ namespace Server.Commands CommandSystem.Register("TelGenDelete", AccessLevel.Administrator, TelGenDelete_OnCommand); } - [Usage("TelGenDelete"), Description("Destroys world/dungeon teleporters for all facets.")] + [Usage("TelGenDelete")] + [Description("Destroys world/dungeon teleporters for all facets.")] public static void TelGenDelete_OnCommand(CommandEventArgs e) { var from = e.Mobile; @@ -63,7 +64,8 @@ namespace Server.Commands from.SendMessage(WarningHue, $"{count} Teleporters Removed."); } - [Usage("TelGen"), Description("Generates world/dungeon teleporters for all facets.")] + [Usage("TelGen")] + [Description("Generates world/dungeon teleporters for all facets.")] public static void GenTeleporter_OnCommand(CommandEventArgs e) { var from = e.Mobile; diff --git a/Projects/UOContent/Commands/Profiling.cs b/Projects/UOContent/Commands/Profiling.cs index 79f035202..b23f21523 100644 --- a/Projects/UOContent/Commands/Profiling.cs +++ b/Projects/UOContent/Commands/Profiling.cs @@ -19,7 +19,8 @@ namespace Server.Commands CommandSystem.Register("SetProfiles", AccessLevel.Administrator, SetProfiles_OnCommand); } - [Usage("WriteProfiles"), Description("Generates a log files containing performance diagnostic information.")] + [Usage("WriteProfiles")] + [Description("Generates a log files containing performance diagnostic information.")] public static void WriteProfiles_OnCommand(CommandEventArgs e) { try @@ -86,7 +87,8 @@ namespace Server.Commands } } - [Usage("CountObjects"), Description("Generates a log file detailing all item and mobile types in the world.")] + [Usage("CountObjects")] + [Description("Generates a log file detailing all item and mobile types in the world.")] public static void CountObjects_OnCommand(CommandEventArgs e) { using (var op = new StreamWriter("objects.log")) @@ -140,7 +142,8 @@ namespace Server.Commands e.Mobile.SendMessage("Object table has been generated. See the file : objects.log"); } - [Usage("TraceExpanded"), Description("Generates a log file describing all items using expanded memory.")] + [Usage("TraceExpanded")] + [Description("Generates a log file describing all items using expanded memory.")] public static void TraceExpanded_OnCommand(CommandEventArgs e) { var typeTable = new Dictionary(); @@ -251,7 +254,8 @@ namespace Server.Commands } } - [Usage("TraceInternal"), Description("Generates a log file describing all items in the 'internal' map.")] + [Usage("TraceInternal")] + [Description("Generates a log file describing all items in the 'internal' map.")] public static void TraceInternal_OnCommand(CommandEventArgs e) { var totalCount = 0; diff --git a/Projects/UOContent/Commands/ResetStaffDress.cs b/Projects/UOContent/Commands/ResetStaffDress.cs new file mode 100644 index 000000000..4ca756b84 --- /dev/null +++ b/Projects/UOContent/Commands/ResetStaffDress.cs @@ -0,0 +1,69 @@ +using System; +using Server.Items; +using Server.Mobiles; +using Server.Network; +using Server.Utilities; + +namespace Server.Commands; + +public static class StaffDress +{ + private static readonly Type[] _staffRobeTypes = + { + null, + typeof(CounselorRobe), + typeof(GMRobe), + typeof(SeerRobe), + typeof(AdminRobe), + typeof(AdminRobe), + typeof(AdminRobe) + }; + + public static void Initialize() + { + CommandSystem.Register("ResetStaffDress", AccessLevel.Counselor, StaffDress_OnCommand); + } + + [Usage("ResetStaffDress")] + [Description("Resets staff to proper GM")] + public static void StaffDress_OnCommand(CommandEventArgs e) + { + if (e.Mobile is not PlayerMobile pm) + { + return; + } + + pm.Karma = pm.Fame = pm.Kills = pm.ShortTermMurders = pm.BodyMod = 0; + pm.Body = 987; + pm.SolidHueOverride = pm.HueMod = -1; + pm.Blessed = true; + pm.DisplayGuildTitle = false; + pm.DisplayChampionTitle = false; + if (pm.Mount != null) + { + pm.Mount.Rider = null; + } + + pm.NetState.SendSpeedControl(SpeedControlSetting.Mount); + pm.ResetStaffAccess(); + + for (var i = pm.Items.Count - 1; i >= 0; i--) + { + var item = pm.Items[i]; + + if (item.Layer is not Layer.Backpack + and not Layer.Bank + and not Layer.FacialHair + and not Layer.Hair + and not Layer.Mount + and not Layer.ShopBuy + and not Layer.ShopResale + and not Layer.ShopSell) + { + pm.AddToBackpack(item); + } + } + + pm.AddItem(_staffRobeTypes[(int)pm.AccessLevel].CreateInstance()); + } +} diff --git a/Projects/UOContent/Commands/ShardTime.cs b/Projects/UOContent/Commands/ShardTime.cs index a206d1340..17de8d46a 100644 --- a/Projects/UOContent/Commands/ShardTime.cs +++ b/Projects/UOContent/Commands/ShardTime.cs @@ -9,7 +9,8 @@ namespace Server.Commands CommandSystem.Register("Time", AccessLevel.Player, Time_OnCommand); } - [Usage("Time"), Description("Returns the server's local time.")] + [Usage("Time")] + [Description("Returns the server's local time.")] private static void Time_OnCommand(CommandEventArgs e) { e.Mobile.SendMessage(Core.Now.ToString(CultureInfo.InvariantCulture)); diff --git a/Projects/UOContent/Commands/SignParser.cs b/Projects/UOContent/Commands/SignParser.cs index 0fba2d29a..9f96a4f85 100644 --- a/Projects/UOContent/Commands/SignParser.cs +++ b/Projects/UOContent/Commands/SignParser.cs @@ -15,7 +15,8 @@ namespace Server.Commands CommandSystem.Register("SignGen", AccessLevel.Administrator, SignGen_OnCommand); } - [Usage("SignGen"), Description("Generates world/shop signs on all facets.")] + [Usage("SignGen")] + [Description("Generates world/shop signs on all facets.")] public static void SignGen_OnCommand(CommandEventArgs c) { Parse(c.Mobile); diff --git a/Projects/UOContent/Commands/Skills.cs b/Projects/UOContent/Commands/Skills.cs index 04d525257..900c8a90a 100644 --- a/Projects/UOContent/Commands/Skills.cs +++ b/Projects/UOContent/Commands/Skills.cs @@ -12,7 +12,8 @@ namespace Server.Commands CommandSystem.Register("SetAllSkills", AccessLevel.GameMaster, SetAllSkills_OnCommand); } - [Usage("SetSkill "), Description("Sets a skill value by name of a targeted mobile.")] + [Usage("SetSkill ")] + [Description("Sets a skill value by name of a targeted mobile.")] public static void SetSkill_OnCommand(CommandEventArgs arg) { if (arg.Length != 2) @@ -32,7 +33,8 @@ namespace Server.Commands } } - [Usage("SetAllSkills "), Description("Sets all skill values of a targeted mobile.")] + [Usage("SetAllSkills ")] + [Description("Sets all skill values of a targeted mobile.")] public static void SetAllSkills_OnCommand(CommandEventArgs arg) { if (arg.Length != 1) @@ -45,7 +47,8 @@ namespace Server.Commands } } - [Usage("GetSkill "), Description("Gets a skill value by name of a targeted mobile.")] + [Usage("GetSkill ")] + [Description("Gets a skill value by name of a targeted mobile.")] public static void GetSkill_OnCommand(CommandEventArgs arg) { if (arg.Length != 1) diff --git a/Projects/UOContent/Commands/SkillsMenu.cs b/Projects/UOContent/Commands/SkillsMenu.cs index 956a52c4d..a69e55e1e 100644 --- a/Projects/UOContent/Commands/SkillsMenu.cs +++ b/Projects/UOContent/Commands/SkillsMenu.cs @@ -15,7 +15,8 @@ namespace Server.Commands CommandSystem.Register("Skills", AccessLevel.Counselor, Skills_OnCommand); } - [Usage("Skills"), Description("Opens a menu where you can view or edit skills of a targeted mobile.")] + [Usage("Skills")] + [Description("Opens a menu where you can view or edit skills of a targeted mobile.")] private static void Skills_OnCommand(CommandEventArgs e) { e.Mobile.Target = new SkillsTarget(); diff --git a/Projects/UOContent/Commands/StaffAccess.cs b/Projects/UOContent/Commands/StaffAccess.cs new file mode 100644 index 000000000..47ff71daa --- /dev/null +++ b/Projects/UOContent/Commands/StaffAccess.cs @@ -0,0 +1,101 @@ +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using Server.Accounting; +using Server.Mobiles; + +namespace Server.Commands; + +public static class StaffAccess +{ + private static readonly Dictionary _accessLevelByString = new(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static string AccountTag(Serial serial) => $"OriginalStaffAccess:{serial}"; + + public static void Initialize() + { + CommandSystem.Register("StaffAccess", AccessLevel.Player, StaffAccess_OnCommand); + + foreach (var accessLevel in Enum.GetValues()) + { + _accessLevelByString[accessLevel.ToString().ToLower()] = accessLevel; + } + + _accessLevelByString["gm"] = AccessLevel.GameMaster; + _accessLevelByString["dev"] = AccessLevel.Developer; + _accessLevelByString["admin"] = AccessLevel.Administrator; + } + + public static void ResetStaffAccess(this PlayerMobile m) + { + if (m.Account is not Account account) + { + return; + } + + var accountTag = AccountTag(m.Serial); + var originalAccessLevelString = account.GetTag(accountTag); + if (originalAccessLevelString == null) + { + return; + } + + var accessLevel = _accessLevelByString[originalAccessLevelString]; + account.RemoveTag(accountTag); + m.AccessLevel = accessLevel; + } + + [Usage("StaffAccess ")] + [Description("Overrides your access level.")] + public static void StaffAccess_OnCommand(CommandEventArgs e) + { + var m = e.Mobile; + if (m.Account is not Account account) + { + return; + } + + var accountTag = AccountTag(m.Serial); + var originalAccessLevelString = account.GetTag(accountTag); + AccessLevel? originalAccessLevel = originalAccessLevelString != null ? _accessLevelByString[originalAccessLevelString] : null; + if (originalAccessLevel == null && m.AccessLevel == AccessLevel.Player) + { + return; + } + + var accessLevelArgument = e.GetString(0)?.Trim().ToLower(); + AccessLevel newAccessLevel = AccessLevel.Player; + var validAccessLevel = !string.IsNullOrEmpty(accessLevelArgument) && + _accessLevelByString.TryGetValue(accessLevelArgument, out newAccessLevel); + + if (!validAccessLevel && originalAccessLevel == null) + { + m.SendMessage("Invalid access level specified."); + m.SendMessage("Usage: [staffaccess ."); + return; + } + + if (originalAccessLevel != null && (!validAccessLevel || newAccessLevel == originalAccessLevel)) + { + account.RemoveTag(accountTag); + newAccessLevel = originalAccessLevel.Value; + m.SendMessage("Restoring original staff access..."); + } + + if (newAccessLevel > m.AccessLevel) + { + m.SendMessage($"You cannot set your staff access to {newAccessLevel.ToString()}."); + return; + } + + if (originalAccessLevel == null) + { + // Save the original access level + account.AddTag(accountTag, m.AccessLevel.ToString().ToLower()); + } + + m.AccessLevel = newAccessLevel; + m.SendMessage($"Staff access set to {newAccessLevel.ToString()}."); + } +} diff --git a/Projects/UOContent/Commands/Statics.cs b/Projects/UOContent/Commands/Statics.cs index 839bd0ec3..8a64c3021 100644 --- a/Projects/UOContent/Commands/Statics.cs +++ b/Projects/UOContent/Commands/Statics.cs @@ -48,14 +48,16 @@ namespace Server CommandSystem.Register("UnfreezeWorld", AccessLevel.Administrator, UnfreezeWorld_OnCommand); } - [Usage("Freeze"), Description("Makes a targeted area of dynamic items static.")] + [Usage("Freeze")] + [Description("Makes a targeted area of dynamic items static.")] public static void Freeze_OnCommand(CommandEventArgs e) { var from = e.Mobile; BoundingBoxPicker.Begin(from, (map, start, end) => FreezeBox_Callback(from, map, start, end)); } - [Usage("FreezeMap"), Description("Makes every dynamic item in your map static.")] + [Usage("FreezeMap")] + [Description("Makes every dynamic item in your map static.")] public static void FreezeMap_OnCommand(CommandEventArgs e) { var from = e.Mobile; @@ -75,7 +77,8 @@ namespace Server } } - [Usage("FreezeWorld"), Description("Makes every dynamic item on all maps static.")] + [Usage("FreezeWorld")] + [Description("Makes every dynamic item on all maps static.")] public static void FreezeWorld_OnCommand(CommandEventArgs e) { SendWarning( @@ -404,14 +407,16 @@ namespace Server } } - [Usage("Unfreeze"), Description("Makes a targeted area of static items dynamic.")] + [Usage("Unfreeze")] + [Description("Makes a targeted area of static items dynamic.")] public static void Unfreeze_OnCommand(CommandEventArgs e) { var from = e.Mobile; BoundingBoxPicker.Begin(from, (map, start, end) => UnfreezeBox_Callback(from, map, start, end)); } - [Usage("UnfreezeMap"), Description("Makes every static item in your map dynamic.")] + [Usage("UnfreezeMap")] + [Description("Makes every static item in your map dynamic.")] public static void UnfreezeMap_OnCommand(CommandEventArgs e) { var map = e.Mobile.Map; @@ -430,7 +435,8 @@ namespace Server } } - [Usage("UnfreezeWorld"), Description("Makes every static item on all maps dynamic.")] + [Usage("UnfreezeWorld")] + [Description("Makes every static item on all maps dynamic.")] public static void UnfreezeWorld_OnCommand(CommandEventArgs e) { SendWarning( diff --git a/Projects/UOContent/Commands/VisibilityList.cs b/Projects/UOContent/Commands/VisibilityList.cs index cea19640d..ee871d3dc 100644 --- a/Projects/UOContent/Commands/VisibilityList.cs +++ b/Projects/UOContent/Commands/VisibilityList.cs @@ -22,9 +22,8 @@ namespace Server.Commands (m as PlayerMobile)?.VisibilityList.Clear(); } - [Usage("Vis"), Description( - "Adds or removes a targeted player from your visibility list. Anyone on your visibility list will be able to see you at all times, even when you're hidden." - )] + [Usage("Vis")] + [Description("Adds or removes a targeted player from your visibility list. Anyone on your visibility list will be able to see you at all times, even when you're hidden.")] public static void Vis_OnCommand(CommandEventArgs e) { if (e.Mobile is PlayerMobile) @@ -34,7 +33,8 @@ namespace Server.Commands } } - [Usage("VisList"), Description("Shows the names of everyone in your visibility list.")] + [Usage("VisList")] + [Description("Shows the names of everyone in your visibility list.")] public static void VisList_OnCommand(CommandEventArgs e) { if (e.Mobile is PlayerMobile pm) @@ -57,7 +57,8 @@ namespace Server.Commands } } - [Usage("VisClear"), Description("Removes everyone from your visibility list.")] + [Usage("VisClear")] + [Description("Removes everyone from your visibility list.")] public static void VisClear_OnCommand(CommandEventArgs e) { if (e.Mobile is PlayerMobile pm) diff --git a/Projects/UOContent/Commands/Wipe.cs b/Projects/UOContent/Commands/Wipe.cs index bc066fbde..806ad6a61 100644 --- a/Projects/UOContent/Commands/Wipe.cs +++ b/Projects/UOContent/Commands/Wipe.cs @@ -24,25 +24,29 @@ namespace Server.Commands CommandSystem.Register("WipeMultis", AccessLevel.GameMaster, WipeMultis_OnCommand); } - [Usage("Wipe"), Description("Wipes all items and npcs in a targeted bounding box.")] + [Usage("Wipe")] + [Description("Wipes all items and npcs in a targeted bounding box.")] private static void WipeAll_OnCommand(CommandEventArgs e) { BeginWipe(e.Mobile, WipeType.Items | WipeType.Mobiles); } - [Usage("WipeItems"), Description("Wipes all items in a targeted bounding box.")] + [Usage("WipeItems")] + [Description("Wipes all items in a targeted bounding box.")] private static void WipeItems_OnCommand(CommandEventArgs e) { BeginWipe(e.Mobile, WipeType.Items); } - [Usage("WipeNPCs"), Description("Wipes all npcs in a targeted bounding box.")] + [Usage("WipeNPCs")] + [Description("Wipes all npcs in a targeted bounding box.")] private static void WipeNPCs_OnCommand(CommandEventArgs e) { BeginWipe(e.Mobile, WipeType.Mobiles); } - [Usage("WipeMultis"), Description("Wipes all multis in a targeted bounding box.")] + [Usage("WipeMultis")] + [Description("Wipes all multis in a targeted bounding box.")] private static void WipeMultis_OnCommand(CommandEventArgs e) { BeginWipe(e.Mobile, WipeType.Multis); From 48232829add0268f18ecc0bf9560ba694e2fdadd Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Dec 2021 01:41:35 -0800 Subject: [PATCH 03/19] fix: Reset body hue and facial hair (#896) --- Projects/UOContent/Commands/ResetStaffDress.cs | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/Projects/UOContent/Commands/ResetStaffDress.cs b/Projects/UOContent/Commands/ResetStaffDress.cs index 4ca756b84..3d78b2649 100644 --- a/Projects/UOContent/Commands/ResetStaffDress.cs +++ b/Projects/UOContent/Commands/ResetStaffDress.cs @@ -33,9 +33,11 @@ public static class StaffDress return; } + pm.Race = Race.Human; pm.Karma = pm.Fame = pm.Kills = pm.ShortTermMurders = pm.BodyMod = 0; pm.Body = 987; pm.SolidHueOverride = pm.HueMod = -1; + pm.FacialHairItemID = 0; pm.Blessed = true; pm.DisplayGuildTitle = false; pm.DisplayChampionTitle = false; @@ -47,13 +49,22 @@ public static class StaffDress pm.NetState.SendSpeedControl(SpeedControlSetting.Mount); pm.ResetStaffAccess(); + if (pm.AccessLevel < AccessLevel.Administrator) + { + pm.Hue = Race.Human.ClipSkinHue(pm.Hue & 0x3FFF); + } + for (var i = pm.Items.Count - 1; i >= 0; i--) { var item = pm.Items[i]; + if (item.Layer is Layer.FacialHair) + { + item.Delete(); + } + if (item.Layer is not Layer.Backpack and not Layer.Bank - and not Layer.FacialHair and not Layer.Hair and not Layer.Mount and not Layer.ShopBuy From a87aab19d09f505a7d496f55a9bde00bcb2820cd Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Dec 2021 01:45:13 -0800 Subject: [PATCH 04/19] fix: Fixes setting body hue for resetstaffdress (#897) --- Projects/UOContent/Commands/ResetStaffDress.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/UOContent/Commands/ResetStaffDress.cs b/Projects/UOContent/Commands/ResetStaffDress.cs index 3d78b2649..cd94e0350 100644 --- a/Projects/UOContent/Commands/ResetStaffDress.cs +++ b/Projects/UOContent/Commands/ResetStaffDress.cs @@ -51,7 +51,7 @@ public static class StaffDress if (pm.AccessLevel < AccessLevel.Administrator) { - pm.Hue = Race.Human.ClipSkinHue(pm.Hue & 0x3FFF); + pm.Hue = Race.Human.ClipSkinHue((pm.Hue + 1) & 0x3FFF); } for (var i = pm.Items.Count - 1; i >= 0; i--) From 93f09ba8312f835b41cdf923808a0430cff0c595 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Dec 2021 17:17:45 -0800 Subject: [PATCH 05/19] fix: Fixes account gold settings (#898) --- Projects/Server/Items/SecureTradeContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Server/Items/SecureTradeContainer.cs b/Projects/Server/Items/SecureTradeContainer.cs index 2cc4f39c9..3c28e8089 100644 --- a/Projects/Server/Items/SecureTradeContainer.cs +++ b/Projects/Server/Items/SecureTradeContainer.cs @@ -93,7 +93,7 @@ namespace Server.Items public override bool IsChildVisibleTo(Mobile m, Item child) => child is VirtualCheck - ? !AccountGold.Enabled || m.NetState?.NewSecureTrading != true + ? AccountGold.Enabled && m.NetState is not { NewSecureTrading: true } : base.IsChildVisibleTo(m, child); public override void Serialize(IGenericWriter writer) From dc6caf576629155fcd602c7882e3850ac68e59b1 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 27 Dec 2021 19:38:03 -0800 Subject: [PATCH 06/19] fix: Fixes setting staff access (#899) --- Projects/UOContent/Commands/StaffAccess.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/UOContent/Commands/StaffAccess.cs b/Projects/UOContent/Commands/StaffAccess.cs index 47ff71daa..b853de0e5 100644 --- a/Projects/UOContent/Commands/StaffAccess.cs +++ b/Projects/UOContent/Commands/StaffAccess.cs @@ -83,7 +83,7 @@ public static class StaffAccess m.SendMessage("Restoring original staff access..."); } - if (newAccessLevel > m.AccessLevel) + if ((originalAccessLevel ?? m.AccessLevel) < newAccessLevel) { m.SendMessage($"You cannot set your staff access to {newAccessLevel.ToString()}."); return; From 79dc9fa0f713b339c1011f4bc4dd1371b6ff0785 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 28 Dec 2021 02:09:25 -0800 Subject: [PATCH 07/19] fix: Fixes snooping staff (#900) * Not allowed to snoop staff * Staff that snoop won't broadcast messages * Benchmarks RNG for double vs fixed int --- .../Benchmarks/Rng/BenchmarkDoubleVsFixed.cs | 28 ++++ Projects/Benchmarks/Program.cs | 3 +- Projects/UOContent/Skills/Snooping.cs | 123 +++++++++--------- 3 files changed, 88 insertions(+), 66 deletions(-) create mode 100644 Projects/Benchmarks/Benchmarks/Rng/BenchmarkDoubleVsFixed.cs diff --git a/Projects/Benchmarks/Benchmarks/Rng/BenchmarkDoubleVsFixed.cs b/Projects/Benchmarks/Benchmarks/Rng/BenchmarkDoubleVsFixed.cs new file mode 100644 index 000000000..53b079cb5 --- /dev/null +++ b/Projects/Benchmarks/Benchmarks/Rng/BenchmarkDoubleVsFixed.cs @@ -0,0 +1,28 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using Server.Random; + +namespace Benchmarks.Benchmarks.Rng +{ + [MemoryDiagnoser] + [SimpleJob(RuntimeMoniker.Net60)] + public class BenchmarkDoubleVsFixed + { + private Xoshiro256PlusPlus _xoshiro256PlusPlus; + + [GlobalSetup] + public void Setup() + { + _xoshiro256PlusPlus = new Xoshiro256PlusPlus(); + } + + [Benchmark] + public bool NextDouble() => 50.1 < _xoshiro256PlusPlus.NextDouble() * 100; + + [Benchmark] + public bool NextFixedInt() => 501 < _xoshiro256PlusPlus.Next(1000); + + [Benchmark] + public bool NextHighResDouble() => 50.1 < _xoshiro256PlusPlus.NextDoubleHighRes() * 100; + } +} diff --git a/Projects/Benchmarks/Program.cs b/Projects/Benchmarks/Program.cs index 845354d56..4b5671c0f 100644 --- a/Projects/Benchmarks/Program.cs +++ b/Projects/Benchmarks/Program.cs @@ -15,7 +15,8 @@ namespace Benchmarks // var textEncoding = BenchmarkRunner.Run(); // var logging = BenchmarkRunner.Run(); // var gumpPacket = BenchmarkRunner.Run(); - var rngTest = BenchmarkRunner.Run(); + // var rngTest = BenchmarkRunner.Run(); + var doubleRngText = BenchmarkRunner.Run(); } } } diff --git a/Projects/UOContent/Skills/Snooping.cs b/Projects/UOContent/Skills/Snooping.cs index 73b03bffc..58b28ee24 100644 --- a/Projects/UOContent/Skills/Snooping.cs +++ b/Projects/UOContent/Skills/Snooping.cs @@ -3,68 +3,64 @@ using Server.Misc; using Server.Mobiles; using Server.Regions; -namespace Server.SkillHandlers +namespace Server.SkillHandlers; + +public static class Snooping { - public static class Snooping + public static void Configure() { - public static void Configure() + Container.SnoopHandler = Container_Snoop; + } + + public static bool CheckSnoopAllowed(Mobile from, Mobile to) + { + var map = from.Map; + + if (to.Player) { - Container.SnoopHandler = Container_Snoop; + return from.CanBeHarmful(to, false, true); // normal restrictions } - public static bool CheckSnoopAllowed(Mobile from, Mobile to) + if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) { - var map = from.Map; - - if (to.Player) - { - return from.CanBeHarmful(to, false, true); // normal restrictions - } - - if ((map?.Rules & MapRules.HarmfulRestrictions) == 0) - { - return true; // felucca you can snoop anybody - } - - var reg = to.Region.GetRegion(); - - if (reg?.IsDisabled() != true) - { - return true; // not in town? we can snoop any npc - } - - return !to.Body.IsHuman || to is BaseCreature cret && (cret.AlwaysAttackable || cret.AlwaysMurderer); + return true; // felucca you can snoop anybody } - public static void Container_Snoop(Container cont, Mobile from) + var reg = to.Region.GetRegion(); + + if (reg?.IsDisabled() != true) { - if (from.AccessLevel <= AccessLevel.Player && !from.InRange(cont.GetWorldLocation(), 1)) - { - from.SendLocalizedMessage(500446); // That is too far away. - return; - } + return true; // not in town? we can snoop any npc + } - var root = cont.RootParent as Mobile; + return !to.Body.IsHuman || to is BaseCreature cret && (cret.AlwaysAttackable || cret.AlwaysMurderer); + } - if (root?.Alive == false) - { - return; - } + public static void Container_Snoop(Container cont, Mobile from) + { + if (from.AccessLevel <= AccessLevel.Player && !from.InRange(cont.GetWorldLocation(), 1)) + { + from.SendLocalizedMessage(500446); // That is too far away. + return; + } - if (root?.AccessLevel > AccessLevel.Player && from.AccessLevel == AccessLevel.Player) - { - from.SendLocalizedMessage(500209); // You can not peek into the container. - return; - } + var root = cont.RootParent as Mobile; - if (root?.AccessLevel == AccessLevel.Player && !CheckSnoopAllowed(from, root)) - { - from.SendLocalizedMessage(1001018); // You cannot perform negative acts on your target. - return; - } + if (root?.Alive == false) + { + return; + } - if (root?.AccessLevel == AccessLevel.Player && - from.Skills.Snooping.Value < Utility.Random(100)) + if (root?.AccessLevel > AccessLevel.Player || !CheckSnoopAllowed(from, root)) + { + from.SendLocalizedMessage(1001018); // You cannot perform negative acts on your target. + return; + } + + if (from.AccessLevel == AccessLevel.Player) + { + var snooping = from.Skills.Snooping.Value; + if (root != null && snooping < 100.0 && snooping < Utility.RandomDouble() * 100) { var map = from.Map; @@ -86,28 +82,25 @@ namespace Server.SkillHandlers } } - if (from.AccessLevel == AccessLevel.Player) + Titles.AwardKarma(from, -4, true); + } + + if (from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill(SkillName.Snooping, cont, 0.0, 100.0)) + { + if ((cont as TrappableContainer)?.ExecuteTrap(from) == true) { - Titles.AwardKarma(from, -4, true); + return; } - if (from.AccessLevel > AccessLevel.Player || from.CheckTargetSkill(SkillName.Snooping, cont, 0.0, 100.0)) - { - if (cont is TrappableContainer container && container.ExecuteTrap(from)) - { - return; - } + cont.DisplayTo(from); + } + else + { + from.SendLocalizedMessage(500210); // You failed to peek into the container. - cont.DisplayTo(from); - } - else + if (from.Skills.Hiding.Value / 2 < Utility.RandomDouble() * 100) { - from.SendLocalizedMessage(500210); // You failed to peek into the container. - - if (from.Skills.Hiding.Value / 2 < Utility.Random(100)) - { - from.RevealingAction(); - } + from.RevealingAction(); } } } From d0aa6320f75b597c87f890f8a1101588da21170e Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 28 Dec 2021 02:42:36 -0800 Subject: [PATCH 08/19] feat: Adds instahit option (#901) Enable instahit by adding the setting `"melee.enableInstaHit": "True"` to modernuo.json --- .../UOContent/Items/Weapons/BaseWeapon.cs | 86 +++++++++++-------- 1 file changed, 48 insertions(+), 38 deletions(-) diff --git a/Projects/UOContent/Items/Weapons/BaseWeapon.cs b/Projects/UOContent/Items/Weapons/BaseWeapon.cs index 055c23e8d..2b7b4fd06 100644 --- a/Projects/UOContent/Items/Weapons/BaseWeapon.cs +++ b/Projects/UOContent/Items/Weapons/BaseWeapon.cs @@ -25,6 +25,13 @@ namespace Server.Items public abstract class BaseWeapon : Item, IWeapon, IFactionItem, ICraftable, ISlayer, IDurability { + private static bool _enableInstaHit; + + public static void Configure() + { + _enableInstaHit = ServerConfiguration.GetSetting("melee.enableInstaHit", !Core.UOR); + } + private WeaponAccuracyLevel m_AccuracyLevel; private WeaponAnimation m_Animation; private Mobile m_Crafter; @@ -950,7 +957,10 @@ namespace Server.Items } } - from.NextCombatTime = Core.TickCount + (int)GetDelay(from).TotalMilliseconds; + if (!_enableInstaHit) + { + from.NextCombatTime = Core.TickCount + (int)GetDelay(from).TotalMilliseconds; + } if (UseSkillMod && m_AccuracyLevel != WeaponAccuracyLevel.Regular) { @@ -989,45 +999,45 @@ namespace Server.Items public override void OnRemoved(IEntity parent) { - if (parent is Mobile m) + if (parent is not Mobile m) { - var weapon = m.Weapon as BaseWeapon; - - var modName = Serial.ToString(); - - m.RemoveStatMod($"{modName}Str"); - m.RemoveStatMod($"{modName}Dex"); - m.RemoveStatMod($"{modName}Int"); - - if (weapon != null) - { - m.NextCombatTime = Core.TickCount + (int)weapon.GetDelay(m).TotalMilliseconds; - } - - if (UseSkillMod && m_SkillMod != null) - { - m_SkillMod.Remove(); - m_SkillMod = null; - } - - if (m_MageMod != null) - { - m_MageMod.Remove(); - m_MageMod = null; - } - - if (Core.AOS) - { - SkillBonuses.Remove(); - } - - ImmolatingWeaponSpell.StopImmolating(this); - ForceOfNature.Remove(m); - - m.CheckStatTimers(); - - m.Delta(MobileDelta.WeaponDamage); + return; } + + var modName = Serial.ToString(); + + m.RemoveStatMod($"{modName}Str"); + m.RemoveStatMod($"{modName}Dex"); + m.RemoveStatMod($"{modName}Int"); + + if (!_enableInstaHit && m.Weapon is BaseWeapon weapon) + { + m.NextCombatTime = Core.TickCount + (long)weapon.GetDelay(m).TotalMilliseconds; + } + + if (UseSkillMod && m_SkillMod != null) + { + m_SkillMod.Remove(); + m_SkillMod = null; + } + + if (m_MageMod != null) + { + m_MageMod.Remove(); + m_MageMod = null; + } + + if (Core.AOS) + { + SkillBonuses.Remove(); + } + + ImmolatingWeaponSpell.StopImmolating(this); + ForceOfNature.Remove(m); + + m.CheckStatTimers(); + + m.Delta(MobileDelta.WeaponDamage); } public virtual SkillName GetUsedSkill(Mobile m, bool checkSkillAttrs) From 5019ce9694997300d8ce004f64fb7dec94618499 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 28 Dec 2021 13:48:48 -0800 Subject: [PATCH 09/19] fix: Fixes timer migrations not compiling (#902) --- ...alizationEntityGeneration.ContentStruct.cs | 15 +- .../ISerializableMigrationRule.cs | 10 +- .../Rules/ArrayMigrationRule.cs | 205 ++++----- .../Rules/DictionaryMigrationRule.cs | 431 +++++++++--------- .../Rules/EnumMigrationRule.cs | 79 ++-- .../Rules/HashSetMigrationRule.cs | 273 +++++------ .../Rules/KeyValuePairMigrationRule.cs | 383 ++++++++-------- .../Rules/ListMigrationRule.cs | 275 +++++------ .../Rules/MigrationRule.cs | 36 ++ .../Rules/PrimitiveTypeMigrationRule.cs | 223 ++++----- .../Rules/PrimitiveUOTypeMigrationRule.cs | 95 ++-- .../Rules/RawSerializableMigrationRule.cs | 97 ++-- .../SerializableInterfaceMigrationRule.cs | 83 ++-- ...rializationMethodSignatureMigrationRule.cs | 103 ++--- .../Rules/TimerMigrationRule.cs | 174 +++---- 15 files changed, 1273 insertions(+), 1209 deletions(-) create mode 100644 Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs diff --git a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs index 7e664920e..56544ed60 100644 --- a/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs +++ b/Projects/SerializationGenerator/SerializableEntityGeneration/SerializationEntityGeneration.ContentStruct.cs @@ -37,12 +37,9 @@ namespace SerializationGenerator foreach (var serializableProperty in properties) { - var propertyType = serializableProperty.Type; - var type = compilation.GetTypeByMetadataName(propertyType)?.IsValueType == true - || SymbolMetadata.IsPrimitiveFromTypeDisplayString(propertyType) && propertyType != "bool" - ? $"{propertyType}{(serializableProperty.UsesSaveFlag == true ? "?" : "")}" : propertyType; - - source.AppendLine($"{indent} internal readonly {type} {serializableProperty.Name};"); + SerializableMigrationRulesEngine.Rules[serializableProperty.Rule].GenerateMigrationProperty( + source, compilation, $"{indent} ", serializableProperty + ); } var innerIndent = $"{indent} "; @@ -100,7 +97,8 @@ namespace SerializationGenerator source, $"{innerIndent} ", property, - "entity" + "entity", + true ); source.AppendLine($"{innerIndent}}}\n{innerIndent}else\n{innerIndent}{{"); @@ -114,7 +112,8 @@ namespace SerializationGenerator source, innerIndent, property, - "entity" + "entity", + true ); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs index 1f944c4fa..a64453e33 100644 --- a/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/ISerializableMigrationRule.cs @@ -23,6 +23,13 @@ namespace SerializableMigration { string RuleName { get; } + void GenerateMigrationProperty( + StringBuilder source, + Compilation compilation, + string indent, + SerializableProperty serializableProperty + ); + bool GenerateRuleState( Compilation compilation, ISymbol symbol, @@ -37,7 +44,8 @@ namespace SerializableMigration StringBuilder source, string indent, SerializableProperty property, - string? parentReference + string? parentReference, + bool isMigration = false ); void GenerateSerializationMethod( diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs index 54b63cc1c..99a1e911e 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ArrayMigrationRule.cs @@ -18,117 +18,118 @@ using System.Collections.Immutable; using System.Text; using Microsoft.CodeAnalysis; -namespace SerializableMigration +namespace SerializableMigration; + +public class ArrayMigrationRule : MigrationRule { - public class ArrayMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(ArrayMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(ArrayMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not IArrayTypeSymbol arrayTypeSymbol) { - if (symbol is not IArrayTypeSymbol arrayTypeSymbol) - { - ruleArguments = null; - return false; - } - - var serializableArrayType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ArrayEntry", - arrayTypeSymbol.ElementType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var length = serializableArrayType.RuleArguments?.Length?? 0; - ruleArguments = new string[length + 2]; - ruleArguments[0] = arrayTypeSymbol.ElementType.ToDisplayString(); - ruleArguments[1] = serializableArrayType.Rule; - if (length > 0) - { - Array.Copy(serializableArrayType.RuleArguments!, 0, ruleArguments, 2, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var serializableArrayType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ArrayEntry", + arrayTypeSymbol.ElementType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var length = serializableArrayType.RuleArguments?.Length?? 0; + ruleArguments = new string[length + 2]; + ruleArguments[0] = arrayTypeSymbol.ElementType.ToDisplayString(); + ruleArguments[1] = serializableArrayType.Rule; + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - var ruleArguments = property.RuleArguments; - var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; - var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; - Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); - - var propertyIndex = $"{property.Name}Index"; - source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadEncodedInt()];"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableArrayElement = new SerializableProperty - { - Name = $"{property.Name}[{propertyIndex}]", - Type = ruleArguments[0], - Rule = arrayElementRule.RuleName, - RuleArguments = arrayElementRuleArguments - }; - - arrayElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableArrayElement, parentReference); - - source.AppendLine($"{indent}}}"); + Array.Copy(serializableArrayType.RuleArguments!, 0, ruleArguments, 2, length); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; - var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; - Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyLength = $"{propertyVarPrefix}Length"; - source.AppendLine($"{indent}var {propertyLength} = {property.Name}?.Length ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyLength});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyLength}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableArrayElement = new SerializableProperty - { - Name = $"{property.Name}![{propertyIndex}]", - Type = ruleArguments[0], - Rule = arrayElementRule.RuleName, - RuleArguments = arrayElementRuleArguments - }; - - arrayElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableArrayElement); - - source.AppendLine($"{indent}}}"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + var ruleArguments = property.RuleArguments; + var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; + var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; + Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); + + var propertyIndex = $"{property.Name}Index"; + source.AppendLine($"{indent}{property.Name} = new {ruleArguments[0]}[reader.ReadEncodedInt()];"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {property.Name}.Length; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableArrayElement = new SerializableProperty + { + Name = $"{property.Name}[{propertyIndex}]", + Type = ruleArguments[0], + Rule = arrayElementRule.RuleName, + RuleArguments = arrayElementRuleArguments + }; + + arrayElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableArrayElement, parentReference); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var arrayElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![1]]; + var arrayElementRuleArguments = new string[ruleArguments.Length - 2]; + Array.Copy(ruleArguments, 2, arrayElementRuleArguments, 0, ruleArguments.Length - 2); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyLength = $"{propertyVarPrefix}Length"; + source.AppendLine($"{indent}var {propertyLength} = {property.Name}?.Length ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyLength});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyLength}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableArrayElement = new SerializableProperty + { + Name = $"{property.Name}![{propertyIndex}]", + Type = ruleArguments[0], + Rule = arrayElementRule.RuleName, + RuleArguments = arrayElementRuleArguments + }; + + arrayElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableArrayElement); + + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs index 309e4c461..caf0d1dc8 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/DictionaryMigrationRule.cs @@ -20,230 +20,231 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class DictionaryMigrationRule : MigrationRule { - public class DictionaryMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(DictionaryMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(DictionaryMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsDictionary(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsDictionary(compilation)) - { - ruleArguments = null; - return false; - } - - var keySymbolType = namedTypeSymbol.TypeArguments[0]; - - var serializableKeyProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "KeyEntry", - keySymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var valueSymbolType = namedTypeSymbol.TypeArguments[1]; - - var serializableValueProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ValueEntry", - valueSymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0; - var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0; - var index = 0; - - ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength]; - ruleArguments[index++] = extraOptions; - ruleArguments[index++] = keySymbolType.ToDisplayString(); - ruleArguments[index++] = serializableKeyProperty.Rule; - ruleArguments[index++] = keyArgumentsLength.ToString(); - - if (keyArgumentsLength > 0) - { - Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); - index += keyArgumentsLength; - } - - ruleArguments[index++] = valueSymbolType.ToDisplayString(); - ruleArguments[index++] = serializableValueProperty.Rule; - ruleArguments[index++] = valueArgumentsLength.ToString(); - - if (valueArgumentsLength > 0) - { - Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var keySymbolType = namedTypeSymbol.TypeArguments[0]; + + var serializableKeyProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "KeyEntry", + keySymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var valueSymbolType = namedTypeSymbol.TypeArguments[1]; + + var serializableValueProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ValueEntry", + valueSymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; - var keyType = ruleArguments![index++]; - - var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var valueType = ruleArguments[index++]; - var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyKeyEntry = $"{propertyVarPrefix}Key"; - var propertyValueEntry = $"{propertyVarPrefix}Value"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};"); - source.AppendLine($"{indent}{valueType} {propertyValueEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableKeyElement = new SerializableProperty - { - Name = propertyKeyEntry, - Type = keyType, - Rule = keyElementRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableKeyElement, parentReference); - - var serializableValueElement = new SerializableProperty - { - Name = propertyValueEntry, - Type = valueType, - Rule = valueElementRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableValueElement, parentReference); - source.AppendLine($"{indent} {propertyName}.Add({propertyKeyEntry}, {propertyValueEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var keyArgumentsLength = serializableKeyProperty.RuleArguments?.Length ?? 0; + var valueArgumentsLength = serializableValueProperty.RuleArguments?.Length ?? 0; + var index = 0; + + ruleArguments = new string[7 + keyArgumentsLength + valueArgumentsLength]; + ruleArguments[index++] = extraOptions; + ruleArguments[index++] = keySymbolType.ToDisplayString(); + ruleArguments[index++] = serializableKeyProperty.Rule; + ruleArguments[index++] = keyArgumentsLength.ToString(); + + if (keyArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 0; - var shouldTidy = ruleArguments![index++].Contains("@Tidy"); - var keyType = ruleArguments![index++]; - - var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var valueType = ruleArguments[index++]; - var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyKeyEntry = $"{propertyVarPrefix}Key"; - var propertyValueEntry = $"{propertyVarPrefix}Value"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var ({propertyKeyEntry}, {propertyValueEntry}) in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableKeyElement = new SerializableProperty - { - Name = propertyKeyEntry, - Type = keyType, - Rule = keyElementRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableKeyElement); - - var serializableValueElement = new SerializableProperty - { - Name = propertyValueEntry, - Type = valueType, - Rule = valueElementRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableKeyProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); + index += keyArgumentsLength; } + + ruleArguments[index++] = valueSymbolType.ToDisplayString(); + ruleArguments[index++] = serializableValueProperty.Rule; + ruleArguments[index++] = valueArgumentsLength.ToString(); + + if (valueArgumentsLength > 0) + { + Array.Copy(serializableValueProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); + } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; + var keyType = ruleArguments![index++]; + + var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var valueType = ruleArguments[index++]; + var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyKeyEntry = $"{propertyVarPrefix}Key"; + var propertyValueEntry = $"{propertyVarPrefix}Value"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[1]} {propertyKeyEntry};"); + source.AppendLine($"{indent}{valueType} {propertyValueEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.Dictionary<{keyType}, {valueType}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableKeyElement = new SerializableProperty + { + Name = propertyKeyEntry, + Type = keyType, + Rule = keyElementRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableKeyElement, parentReference); + + var serializableValueElement = new SerializableProperty + { + Name = propertyValueEntry, + Type = valueType, + Rule = valueElementRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableValueElement, parentReference); + source.AppendLine($"{indent} {propertyName}.Add({propertyKeyEntry}, {propertyValueEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 0; + var shouldTidy = ruleArguments![index++].Contains("@Tidy"); + var keyType = ruleArguments![index++]; + + var keyElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments![index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var valueType = ruleArguments[index++]; + var valueElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyKeyEntry = $"{propertyVarPrefix}Key"; + var propertyValueEntry = $"{propertyVarPrefix}Value"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var ({propertyKeyEntry}, {propertyValueEntry}) in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableKeyElement = new SerializableProperty + { + Name = propertyKeyEntry, + Type = keyType, + Rule = keyElementRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableKeyElement); + + var serializableValueElement = new SerializableProperty + { + Name = propertyValueEntry, + Type = valueType, + Rule = valueElementRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableValueElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs index 18ebc3678..5e8d7fd45 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/EnumMigrationRule.cs @@ -19,54 +19,55 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class EnumMigrationRule : MigrationRule { - public class EnumMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(EnumMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(EnumMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not ITypeSymbol typeSymbol || !typeSymbol.IsEnum()) { - if (symbol is not ITypeSymbol typeSymbol || !typeSymbol.IsEnum()) - { - ruleArguments = null; - return false; - } - - ruleArguments = Array.Empty(); - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = Array.Empty(); + return true; + } - source.AppendLine($"{indent}{property.Name} = reader.ReadEnum<{property.Type}>();"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + source.AppendLine($"{indent}{property.Name} = reader.ReadEnum<{property.Type}>();"); + } - source.AppendLine($"{indent}writer.WriteEnum<{property.Type}>({property.Name});"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + source.AppendLine($"{indent}writer.WriteEnum<{property.Type}>({property.Name});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs index d670ae01f..20fe03d08 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/HashSetMigrationRule.cs @@ -20,151 +20,152 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class HashSetMigrationRule : MigrationRule { - public class HashSetMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(HashSetMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(HashSetMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsHashSet(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsHashSet(compilation)) - { - ruleArguments = null; - return false; - } - - var setTypeSymbol = namedTypeSymbol.TypeArguments[0]; - - var serializableSetType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "SetEntry", - setTypeSymbol, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var length = serializableSetType.RuleArguments?.Length ?? 0; - ruleArguments = new string[length + 3]; - ruleArguments[0] = extraOptions; - ruleArguments[1] = setTypeSymbol.ToDisplayString(); - ruleArguments[2] = serializableSetType.Rule; - - if (length > 0) - { - Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var setTypeSymbol = namedTypeSymbol.TypeArguments[0]; + + var serializableSetType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "SetEntry", + setTypeSymbol, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableSetElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = setElementRule.RuleName, - RuleArguments = setElementRuleArguments - }; - - setElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableSetElement, parentReference); - source.AppendLine($"{indent} {property.Name}.Add({propertyEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var length = serializableSetType.RuleArguments?.Length ?? 0; + ruleArguments = new string[length + 3]; + ruleArguments[0] = extraOptions; + ruleArguments[1] = setTypeSymbol.ToDisplayString(); + ruleArguments[2] = serializableSetType.Rule; + + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableSetElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = setElementRule.RuleName, - RuleArguments = setElementRuleArguments - }; - - setElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableSetElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableSetType.RuleArguments, 0, ruleArguments, 3, length); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{property.Name} = new System.Collections.Generic.HashSet<{ruleArguments[argumentsOffset]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableSetElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = setElementRule.RuleName, + RuleArguments = setElementRuleArguments + }; + + setElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableSetElement, parentReference); + source.AppendLine($"{indent} {property.Name}.Add({propertyEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var setElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var setElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, setElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableSetElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = setElementRule.RuleName, + RuleArguments = setElementRuleArguments + }; + + setElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableSetElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs index 1797764c1..5b7c4fbef 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/KeyValuePairMigrationRule.cs @@ -19,206 +19,207 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class KeyValuePairMigrationRule : MigrationRule { - public class KeyValuePairMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(KeyValuePairMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(KeyValuePairMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsKeyValuePair(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsKeyValuePair(compilation)) - { - ruleArguments = null; - return false; - } - - var keySymbolType = namedTypeSymbol.TypeArguments[0]; - - var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "key", - keySymbolType, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var valueSymbolType = namedTypeSymbol.TypeArguments[1]; - - var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "value", - valueSymbolType, - 1, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var keyArgumentsLength = keySerializedProperty.RuleArguments?.Length ?? 0; - var valueArgumentsLength = valueSerializedProperty.RuleArguments?.Length ?? 0; - var index = 0; - - // Key - ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength]; - ruleArguments[index++] = ""; // Extra options - ruleArguments[index++] = keySymbolType.ToDisplayString(); - ruleArguments[index++] = keySerializedProperty.Rule; - ruleArguments[index++] = keyArgumentsLength.ToString(); - if (keyArgumentsLength > 0) - { - Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); - index += keyArgumentsLength; - } - - // Value - ruleArguments[index++] = valueSymbolType.ToDisplayString(); - ruleArguments[index++] = valueSerializedProperty.Rule; - - if (valueArgumentsLength > 0) - { - Array.Copy(valueSerializedProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var keySymbolType = namedTypeSymbol.TypeArguments[0]; + + var keySerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "key", + keySymbolType, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var valueSymbolType = namedTypeSymbol.TypeArguments[1]; + + var valueSerializedProperty = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "value", + valueSymbolType, + 1, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var keyArgumentsLength = keySerializedProperty.RuleArguments?.Length ?? 0; + var valueArgumentsLength = valueSerializedProperty.RuleArguments?.Length ?? 0; + var index = 0; + + // Key + ruleArguments = new string[6 + keyArgumentsLength + valueArgumentsLength]; + ruleArguments[index++] = ""; // Extra options + ruleArguments[index++] = keySymbolType.ToDisplayString(); + ruleArguments[index++] = keySerializedProperty.Rule; + ruleArguments[index++] = keyArgumentsLength.ToString(); + if (keyArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; // skip extra options - var keyType = ruleArguments![index++]; - var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var serializableKeyProperty = new SerializableProperty - { - Name = "key", - Type = keyType, - Rule = keyRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyRule.GenerateDeserializationMethod( - source, - indent, - serializableKeyProperty, - parentReference - ); - - var valueType = ruleArguments[index++]; - var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var serializableValueProperty = new SerializableProperty - { - Name = "value", - Type = valueType, - Rule = valueRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueRule.GenerateDeserializationMethod( - source, - indent, - serializableValueProperty, - parentReference - ); - - source.AppendLine( - $"{indent}{property.Name} = new {SymbolMetadata.KEYVALUEPAIR_STRUCT}<{keyType}, {valueType}>(key, value);" - ); + Array.Copy(keySerializedProperty.RuleArguments!, 0, ruleArguments, index, keyArgumentsLength); + index += keyArgumentsLength; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + // Value + ruleArguments[index++] = valueSymbolType.ToDisplayString(); + ruleArguments[index++] = valueSerializedProperty.Rule; + + if (valueArgumentsLength > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var index = 1; // skip extra options - var keyType = ruleArguments![index++]; - var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (keyRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); - index += keyRuleArguments.Length; - } - - var serializableKeyProperty = new SerializableProperty - { - Name = $"{property.Name}.Key", - Type = keyType, - Rule = keyRule.RuleName, - RuleArguments = keyRuleArguments - }; - - keyRule.GenerateSerializationMethod( - source, - indent, - serializableKeyProperty - ); - - var valueType = ruleArguments[index++]; - var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; - var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; - - if (valueRuleArguments.Length > 0) - { - Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); - } - - var serializableValueProperty = new SerializableProperty - { - Name = $"{property.Name}.Value", - Type = valueType, - Rule = valueRule.RuleName, - RuleArguments = valueRuleArguments - }; - - valueRule.GenerateSerializationMethod( - source, - indent, - serializableValueProperty - ); + Array.Copy(valueSerializedProperty.RuleArguments!, 0, ruleArguments, index, valueArgumentsLength); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; // skip extra options + var keyType = ruleArguments![index++]; + var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var serializableKeyProperty = new SerializableProperty + { + Name = "key", + Type = keyType, + Rule = keyRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyRule.GenerateDeserializationMethod( + source, + indent, + serializableKeyProperty, + parentReference + ); + + var valueType = ruleArguments[index++]; + var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var serializableValueProperty = new SerializableProperty + { + Name = "value", + Type = valueType, + Rule = valueRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueRule.GenerateDeserializationMethod( + source, + indent, + serializableValueProperty, + parentReference + ); + + source.AppendLine( + $"{indent}{property.Name} = new {SymbolMetadata.KEYVALUEPAIR_STRUCT}<{keyType}, {valueType}>(key, value);" + ); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var index = 1; // skip extra options + var keyType = ruleArguments![index++]; + var keyRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var keyRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (keyRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, keyRuleArguments, 0, keyRuleArguments.Length); + index += keyRuleArguments.Length; + } + + var serializableKeyProperty = new SerializableProperty + { + Name = $"{property.Name}.Key", + Type = keyType, + Rule = keyRule.RuleName, + RuleArguments = keyRuleArguments + }; + + keyRule.GenerateSerializationMethod( + source, + indent, + serializableKeyProperty + ); + + var valueType = ruleArguments[index++]; + var valueRule = SerializableMigrationRulesEngine.Rules[ruleArguments[index++]]; + var valueRuleArguments = new string[int.Parse(ruleArguments[index++])]; + + if (valueRuleArguments.Length > 0) + { + Array.Copy(ruleArguments, index, valueRuleArguments, 0, valueRuleArguments.Length); + } + + var serializableValueProperty = new SerializableProperty + { + Name = $"{property.Name}.Value", + Type = valueType, + Rule = valueRule.RuleName, + RuleArguments = valueRuleArguments + }; + + valueRule.GenerateSerializationMethod( + source, + indent, + serializableValueProperty + ); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs index f11e3f369..53d2d2c44 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/ListMigrationRule.cs @@ -20,152 +20,153 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class ListMigrationRule : MigrationRule { - public class ListMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(ListMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(ListMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsList(compilation)) { - if (symbol is not INamedTypeSymbol namedTypeSymbol || !symbol.IsList(compilation)) - { - ruleArguments = null; - return false; - } - - var listTypeSymbol = namedTypeSymbol.TypeArguments[0]; - - var serializableListType = SerializableMigrationRulesEngine.GenerateSerializableProperty( - compilation, - "ListEntry", - listTypeSymbol, - 0, - attributes, - serializableTypes, - embeddedSerializableTypes, - parentSymbol, - null - ); - - var extraOptions = ""; - if (attributes.Any(a => a.IsTidy(compilation))) - { - extraOptions += "@Tidy"; - } - - var length = serializableListType.RuleArguments?.Length ?? 0; - ruleArguments = new string[length + 3]; - ruleArguments[0] = extraOptions; - ruleArguments[1] = listTypeSymbol.ToDisplayString(); - ruleArguments[2] = serializableListType.Rule; - - if (length > 0) - { - Array.Copy(serializableListType.RuleArguments!, 0, ruleArguments, 3, length); - } - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + var listTypeSymbol = namedTypeSymbol.TypeArguments[0]; + + var serializableListType = SerializableMigrationRulesEngine.GenerateSerializableProperty( + compilation, + "ListEntry", + listTypeSymbol, + 0, + attributes, + serializableTypes, + embeddedSerializableTypes, + parentSymbol, + null + ); + + var extraOptions = ""; + if (attributes.Any(a => a.IsTidy(compilation))) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]]; - - var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyIndex = $"{propertyVarPrefix}Index"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); - source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); - source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});"); - source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); - source.AppendLine($"{indent}{{"); - - var serializableListElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = listElementRule.RuleName, - RuleArguments = listElementRuleArguments - }; - - listElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableListElement, parentReference); - source.AppendLine($"{indent} {propertyName}.Add({propertyEntry});"); - - source.AppendLine($"{indent}}}"); + extraOptions += "@Tidy"; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var length = serializableListType.RuleArguments?.Length ?? 0; + ruleArguments = new string[length + 3]; + ruleArguments[0] = extraOptions; + ruleArguments[1] = listTypeSymbol.ToDisplayString(); + ruleArguments[2] = serializableListType.Rule; + + if (length > 0) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var ruleArguments = property.RuleArguments; - var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); - var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); - var argumentsOffset = hasExtraOptions ? 1 : 0; - - var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; - var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; - Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); - - var propertyName = property.Name; - var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; - var propertyEntry = $"{propertyVarPrefix}Entry"; - var propertyCount = $"{propertyVarPrefix}Count"; - - if (shouldTidy) - { - source.AppendLine($"{indent}{property.Name}?.Tidy();"); - } - source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); - source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); - source.AppendLine($"{indent}if ({propertyCount} > 0)"); - source.AppendLine($"{indent}{{"); - source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); - source.AppendLine($"{indent} {{"); - - var serializableListElement = new SerializableProperty - { - Name = propertyEntry, - Type = ruleArguments[argumentsOffset], - Rule = listElementRule.RuleName, - RuleArguments = listElementRuleArguments - }; - - listElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableListElement); - - source.AppendLine($"{indent} }}"); - source.AppendLine($"{indent}}}"); + Array.Copy(serializableListType.RuleArguments!, 0, ruleArguments, 3, length); } + + return true; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[argumentsOffset + 1]]; + + var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyIndex = $"{propertyVarPrefix}Index"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + source.AppendLine($"{indent}{ruleArguments[argumentsOffset]} {propertyEntry};"); + source.AppendLine($"{indent}var {propertyCount} = reader.ReadEncodedInt();"); + source.AppendLine($"{indent}{propertyName} = new System.Collections.Generic.List<{ruleArguments[argumentsOffset]}>({propertyCount});"); + source.AppendLine($"{indent}for (var {propertyIndex} = 0; {propertyIndex} < {propertyCount}; {propertyIndex}++)"); + source.AppendLine($"{indent}{{"); + + var serializableListElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = listElementRule.RuleName, + RuleArguments = listElementRuleArguments + }; + + listElementRule.GenerateDeserializationMethod(source, $"{indent} ", serializableListElement, parentReference); + source.AppendLine($"{indent} {propertyName}.Add({propertyEntry});"); + + source.AppendLine($"{indent}}}"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var ruleArguments = property.RuleArguments; + var hasExtraOptions = ruleArguments![0] == "" || ruleArguments[0].StartsWith("@", StringComparison.Ordinal); + var shouldTidy = hasExtraOptions && ruleArguments[0].Contains("@Tidy"); + var argumentsOffset = hasExtraOptions ? 1 : 0; + + var listElementRule = SerializableMigrationRulesEngine.Rules[ruleArguments[1 + argumentsOffset]]; + var listElementRuleArguments = new string[ruleArguments.Length - 2 - argumentsOffset]; + Array.Copy(ruleArguments, 2 + argumentsOffset, listElementRuleArguments, 0, ruleArguments.Length - 2 - argumentsOffset); + + var propertyName = property.Name; + var propertyVarPrefix = $"{char.ToLower(propertyName[0])}{propertyName.Substring(1, propertyName.Length - 1)}"; + var propertyEntry = $"{propertyVarPrefix}Entry"; + var propertyCount = $"{propertyVarPrefix}Count"; + + if (shouldTidy) + { + source.AppendLine($"{indent}{property.Name}?.Tidy();"); + } + source.AppendLine($"{indent}var {propertyCount} = {property.Name}?.Count ?? 0;"); + source.AppendLine($"{indent}writer.WriteEncodedInt({propertyCount});"); + source.AppendLine($"{indent}if ({propertyCount} > 0)"); + source.AppendLine($"{indent}{{"); + source.AppendLine($"{indent} foreach (var {propertyEntry} in {property.Name}!)"); + source.AppendLine($"{indent} {{"); + + var serializableListElement = new SerializableProperty + { + Name = propertyEntry, + Type = ruleArguments[argumentsOffset], + Rule = listElementRule.RuleName, + RuleArguments = listElementRuleArguments + }; + + listElementRule.GenerateSerializationMethod(source, $"{indent} ", serializableListElement); + + source.AppendLine($"{indent} }}"); + source.AppendLine($"{indent}}}"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs new file mode 100644 index 000000000..848812b54 --- /dev/null +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/MigrationRule.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Immutable; +using System.Text; +using Microsoft.CodeAnalysis; +using SerializationGenerator; + +namespace SerializableMigration; + +public abstract class MigrationRule : ISerializableMigrationRule +{ + public abstract string RuleName { get; } + + public virtual void GenerateMigrationProperty( + StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty + ) + { + var propertyType = serializableProperty.Type; + var type = compilation.GetTypeByMetadataName(propertyType)?.IsValueType == true + || SymbolMetadata.IsPrimitiveFromTypeDisplayString(propertyType) && propertyType != "bool" + ? $"{propertyType}{(serializableProperty.UsesSaveFlag == true ? "?" : "")}" : propertyType; + + source.AppendLine($"{indent}internal readonly {type} {serializableProperty.Name};"); + } + + public abstract bool GenerateRuleState( + Compilation compilation, ISymbol symbol, ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, ISymbol? parentSymbol, out string[] ruleArguments + ); + + public abstract void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ); + + public abstract void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property); +} diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs index f3d8135bd..70b34ce06 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveTypeMigrationRule.cs @@ -20,129 +20,130 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class PrimitiveTypeMigrationRule : MigrationRule { - public class PrimitiveTypeMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(PrimitiveTypeMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(PrimitiveTypeMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation)) { - if (symbol.IsIpAddress(compilation) || symbol.IsTimeSpan(compilation)) - { - ruleArguments = Array.Empty(); - return true; - } - - if ( - symbol is not ITypeSymbol { - SpecialType: not (not - SpecialType.System_Boolean and not - SpecialType.System_SByte and not - SpecialType.System_Int16 and not - SpecialType.System_Int32 and not - SpecialType.System_Int64 and not - SpecialType.System_Byte and not - SpecialType.System_UInt16 and not - SpecialType.System_UInt32 and not - SpecialType.System_UInt64 and not - SpecialType.System_Single and not - SpecialType.System_Double and not - SpecialType.System_String and not - SpecialType.System_Decimal and not - SpecialType.System_DateTime) - } typeSymbol - ) - { - ruleArguments = null; - return false; - } - - ruleArguments = typeSymbol.SpecialType switch - { - SpecialType.System_Int32 when attributes.Any(a => a.IsEncodedInt(compilation)) => - new[] { "EncodedInt" }, - SpecialType.System_DateTime when attributes.Any(a => a.IsDeltaDateTime(compilation)) => - new[] { "DeltaTime" }, - SpecialType.System_String when attributes.Any(a => a.IsInternString(compilation)) => - new[] { "InternString" }, - _ => new[] { "" } - }; - + ruleArguments = Array.Empty(); return true; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if ( + symbol is not ITypeSymbol { + SpecialType: not (not + SpecialType.System_Boolean and not + SpecialType.System_SByte and not + SpecialType.System_Int16 and not + SpecialType.System_Int32 and not + SpecialType.System_Int64 and not + SpecialType.System_Byte and not + SpecialType.System_UInt16 and not + SpecialType.System_UInt32 and not + SpecialType.System_UInt64 and not + SpecialType.System_Single and not + SpecialType.System_Double and not + SpecialType.System_String and not + SpecialType.System_Decimal and not + SpecialType.System_DateTime) + } typeSymbol + ) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; - - const string ipAddress = SymbolMetadata.IPADDRESS_CLASS; - const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT; - const string date = "System.DateTime"; - - var readMethod = property.Type switch - { - "bool" => "ReadBool", - "sbyte" => "ReadSByte", - "short" => "ReadShort", - "int" when argument == "EncodedInt" => "ReadEncodedInt", - "int" => "ReadInt", - "long" => "ReadLong", - "byte" => "ReadByte", - "ushort" => "ReadUShort", - "uint" => "ReadUInt", - "ulong" => "ReadULong", - "float" => "ReadFloat", - "double" => "ReadDouble", - "string" => "ReadString", - "decimal" => "ReadDecimal", - date when argument == "DeltaTime" => "ReadDeltaTime", - date => "ReadDateTime", - ipAddress => "ReadIPAddress", - timeSpan => "ReadTimeSpan" - }; - - var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : ""; - - source.AppendLine($"{indent}{propertyName} = reader.{readMethod}({readArgument});"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + ruleArguments = typeSymbol.SpecialType switch { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + SpecialType.System_Int32 when attributes.Any(a => a.IsEncodedInt(compilation)) => + new[] { "EncodedInt" }, + SpecialType.System_DateTime when attributes.Any(a => a.IsDeltaDateTime(compilation)) => + new[] { "DeltaTime" }, + SpecialType.System_String when attributes.Any(a => a.IsInternString(compilation)) => + new[] { "InternString" }, + _ => new[] { "" } + }; - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + return true; + } - var writeMethod = property.Type switch - { - "System.DateTime" when argument == "DeltaTime" => "WriteDeltaTime", - "int" when argument == "EncodedInt" => "WriteEncodedInt", - _ => "Write" - }; - - source.AppendLine($"{indent}writer.{writeMethod}({propertyName});"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + + const string ipAddress = SymbolMetadata.IPADDRESS_CLASS; + const string timeSpan = SymbolMetadata.TIMESPAN_STRUCT; + const string date = "System.DateTime"; + + var readMethod = property.Type switch + { + "bool" => "ReadBool", + "sbyte" => "ReadSByte", + "short" => "ReadShort", + "int" when argument == "EncodedInt" => "ReadEncodedInt", + "int" => "ReadInt", + "long" => "ReadLong", + "byte" => "ReadByte", + "ushort" => "ReadUShort", + "uint" => "ReadUInt", + "ulong" => "ReadULong", + "float" => "ReadFloat", + "double" => "ReadDouble", + "string" => "ReadString", + "decimal" => "ReadDecimal", + date when argument == "DeltaTime" => "ReadDeltaTime", + date => "ReadDateTime", + ipAddress => "ReadIPAddress", + timeSpan => "ReadTimeSpan" + }; + + var readArgument = readMethod == "ReadString" && argument == "InternString" ? "true" : ""; + + source.AppendLine($"{indent}{propertyName} = reader.{readMethod}({readArgument});"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 ? property.RuleArguments[0] : null; + + var writeMethod = property.Type switch + { + "System.DateTime" when argument == "DeltaTime" => "WriteDeltaTime", + "int" when argument == "EncodedInt" => "WriteEncodedInt", + _ => "Write" + }; + + source.AppendLine($"{indent}writer.{writeMethod}({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs index 9d60ca27e..ec2ea15d3 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/PrimitiveUOTypeMigrationRule.cs @@ -19,61 +19,62 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class PrimitiveUOTypeMigrationRule : MigrationRule { - public class PrimitiveUOTypeMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(PrimitiveUOTypeMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(PrimitiveUOTypeMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + ruleArguments = symbol switch { - ruleArguments = symbol switch - { - _ when symbol.IsPoint2D(compilation) => new[] { "Point2D" }, - _ when symbol.IsPoint3D(compilation) => new[] { "Point3D" }, - _ when symbol.IsRectangle2D(compilation) => new[] { "Rect2D" }, - _ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" }, - _ when symbol.IsRace(compilation) => new[] { "Race" }, - _ when symbol.IsMap(compilation) => new[] { "Map" }, - _ when symbol.IsBitArray(compilation) => new[] { "BitArray" }, - _ => null - }; + _ when symbol.IsPoint2D(compilation) => new[] { "Point2D" }, + _ when symbol.IsPoint3D(compilation) => new[] { "Point3D" }, + _ when symbol.IsRectangle2D(compilation) => new[] { "Rect2D" }, + _ when symbol.IsRectangle3D(compilation) => new[] { "Rect3D" }, + _ when symbol.IsRace(compilation) => new[] { "Race" }, + _ when symbol.IsMap(compilation) => new[] { "Map" }, + _ when symbol.IsBitArray(compilation) => new[] { "BitArray" }, + _ => null + }; - return ruleArguments != null; + return ruleArguments != null; + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = reader.Read{property.RuleArguments?[0] ?? ""}();"); + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = reader.Read{property.RuleArguments?[0] ?? ""}();"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - source.AppendLine($"{indent}writer.Write({propertyName});"); - } + var propertyName = property.Name; + source.AppendLine($"{indent}writer.Write({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs index e5ee8c725..8f0944f1d 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/RawSerializableMigrationRule.cs @@ -19,63 +19,64 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class RawSerializableMigrationRule : MigrationRule { - public class RawSerializableMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(RawSerializableMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(RawSerializableMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is not ITypeSymbol typeSymbol) { - if (symbol is not ITypeSymbol typeSymbol) - { - ruleArguments = null; - return false; - } - - if (!typeSymbol.HasRawSerializableInterface(compilation, embeddedSerializableTypes)) - { - ruleArguments = null; - return false; - } - - ruleArguments = new[] { "" }; - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if (!typeSymbol.HasRawSerializableInterface(compilation, embeddedSerializableTypes)) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = new {property.Type}({parentReference ?? "this"});"); - source.AppendLine($"{indent}{propertyName}.Deserialize(reader);"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = new[] { "" }; + return true; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = new {property.Type}({parentReference ?? "this"});"); + source.AppendLine($"{indent}{propertyName}.Deserialize(reader);"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs index 3cc932c80..2326af110 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializableInterfaceMigrationRule.cs @@ -19,56 +19,57 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class SerializableInterfaceMigrationRule : MigrationRule { - public class SerializableInterfaceMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(SerializableInterfaceMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(SerializableInterfaceMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (symbol is ITypeSymbol typeSymbol && typeSymbol.HasSerializableInterface(compilation, serializableTypes)) { - if (symbol is ITypeSymbol typeSymbol && typeSymbol.HasSerializableInterface(compilation, serializableTypes)) - { - ruleArguments = Array.Empty(); - return true; - } - - ruleArguments = null; - return false; + ruleArguments = Array.Empty(); + return true; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = null; + return false; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName} = reader.ReadEntity<{property.Type}>();"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName} = reader.ReadEntity<{property.Type}>();"); + } - var propertyName = property.Name; - source.AppendLine($"{indent}writer.Write({propertyName});"); + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + source.AppendLine($"{indent}writer.Write({propertyName});"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs index 1cd17971b..4e9859170 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/SerializationMethodSignatureMigrationRule.cs @@ -19,66 +19,67 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class SerializationMethodSignatureMigrationRule : MigrationRule { - public class SerializationMethodSignatureMigrationRule : ISerializableMigrationRule + public override string RuleName => nameof(SerializationMethodSignatureMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(SerializationMethodSignatureMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if ((symbol as ITypeSymbol)?.HasPublicSerializeMethod(compilation, serializableTypes) != true) { - if ((symbol as ITypeSymbol)?.HasPublicSerializeMethod(compilation, serializableTypes) != true) - { - ruleArguments = null; - return false; - } - - if (symbol is not INamedTypeSymbol namedTypeSymbol || - !namedTypeSymbol.HasGenericReaderCtor(compilation, parentSymbol, out var requiresParent)) - { - ruleArguments = null; - return false; - } - - ruleArguments = new[] { requiresParent ? "DeserializationRequiresParent" : "" }; - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + if (symbol is not INamedTypeSymbol namedTypeSymbol || + !namedTypeSymbol.HasGenericReaderCtor(compilation, parentSymbol, out var requiresParent)) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var argument = property.RuleArguments?.Length >= 1 && - property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : ""; - - source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});"); + ruleArguments = null; + return false; } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) - { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } + ruleArguments = new[] { requiresParent ? "DeserializationRequiresParent" : "" }; + return true; + } - var propertyName = property.Name; - source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } + + var propertyName = property.Name; + var argument = property.RuleArguments?.Length >= 1 && + property.RuleArguments[0] == "DeserializationRequiresParent" ? ", this" : ""; + + source.AppendLine($"{indent}{propertyName} = new {property.Type}(reader{argument});"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) + { + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); + } + + var propertyName = property.Name; + source.AppendLine($"{indent}{propertyName}.Serialize(writer);"); } } diff --git a/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs b/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs index 9fba1913a..7d97dfd6e 100644 --- a/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs +++ b/Projects/SerializationGenerator/SerializableMigration/Rules/TimerMigrationRule.cs @@ -20,107 +20,117 @@ using System.Text; using Microsoft.CodeAnalysis; using SerializationGenerator; -namespace SerializableMigration +namespace SerializableMigration; + +public class TimerMigrationRule : MigrationRule, IPostDeserializeMethod { - public class TimerMigrationRule : ISerializableMigrationRule, IPostDeserializeMethod + public override string RuleName => nameof(TimerMigrationRule); + + public override bool GenerateRuleState( + Compilation compilation, + ISymbol symbol, + ImmutableArray attributes, + ImmutableArray serializableTypes, + ImmutableArray embeddedSerializableTypes, + ISymbol? parentSymbol, + out string[] ruleArguments + ) { - public string RuleName => nameof(TimerMigrationRule); - - public bool GenerateRuleState( - Compilation compilation, - ISymbol symbol, - ImmutableArray attributes, - ImmutableArray serializableTypes, - ImmutableArray embeddedSerializableTypes, - ISymbol? parentSymbol, - out string[] ruleArguments - ) + if (!(symbol is ITypeSymbol typeSymbol && typeSymbol.IsTimer(compilation))) { - if (!(symbol is ITypeSymbol typeSymbol && typeSymbol.IsTimer(compilation))) - { - ruleArguments = null; - return false; - } - - ruleArguments = attributes.Any(a => a.IsTimerDrift(compilation)) - ? new[] { "@TimerDrift" } - : new[] { "" }; - - return true; + ruleArguments = null; + return false; } - public void GenerateDeserializationMethod(StringBuilder source, string indent, SerializableProperty property, string? parentReference) + ruleArguments = attributes.Any(a => a.IsTimerDrift(compilation)) + ? new[] { "@TimerDrift" } + : new[] { "" }; + + return true; + } + + public override void GenerateMigrationProperty( + StringBuilder source, Compilation compilation, string indent, SerializableProperty serializableProperty + ) + { + source.AppendLine($"{indent}internal readonly System.DateTime {serializableProperty.Name}Next;"); + source.AppendLine($"{indent}internal readonly System.TimeSpan {serializableProperty.Name}Delay;"); + } + + public override void GenerateDeserializationMethod( + StringBuilder source, string indent, SerializableProperty property, string? parentReference, bool isMigration = false + ) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var ruleArguments = property.RuleArguments; - var driftTimer = ruleArguments![0].Contains("@TimerDrift"); - - var readTimer = driftTimer ? "reader.ReadDeltaTime()" : "reader.ReadDateTime()"; - source.AppendLine($"{indent}var {propertyName}Next = {readTimer};"); - source.AppendLine($"{indent}var {propertyName}Delay = {propertyName}Next == System.DateTime.MinValue ? System.TimeSpan.MinValue : {propertyName}Next - Core.Now;"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + var propertyName = property.Name; + var ruleArguments = property.RuleArguments; + var driftTimer = ruleArguments![0].Contains("@TimerDrift"); + + var readTimer = driftTimer ? "reader.ReadDeltaTime()" : "reader.ReadDateTime()"; + var useVar = isMigration ? "" : "var "; + source.AppendLine($"{indent}{useVar}{propertyName}Next = {readTimer};"); + source.AppendLine($"{indent}{useVar}{propertyName}Delay = {propertyName}Next == System.DateTime.MinValue ? System.TimeSpan.MinValue : {propertyName}Next - Core.Now;"); + } + + public override void GenerateSerializationMethod(StringBuilder source, string indent, SerializableProperty property) + { + var expectedRule = RuleName; + var ruleName = property.Rule; + if (expectedRule != ruleName) { - var expectedRule = RuleName; - var ruleName = property.Rule; - if (expectedRule != ruleName) - { - throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); - } - - var propertyName = property.Name; - var ruleArguments = property.RuleArguments; - var driftTimer = ruleArguments![0].Contains("@TimerDrift"); - - var writerMethod = driftTimer ? "WriteDeltaTime" : "Write"; - source.AppendLine($"{indent}writer.{writerMethod}({propertyName}?.Next ?? System.DateTime.MinValue);"); + throw new ArgumentException($"Invalid rule applied to property {ruleName}. Expecting {expectedRule}, but received {ruleName}."); } - public void PostDeserializeMethod( - StringBuilder source, string indent, SerializableProperty property, Compilation compilation, INamedTypeSymbol classSymbol - ) - { - var deserializeTimerMethod = classSymbol - .GetMembers() - .OfType() - .FirstOrDefault( - m => + var propertyName = property.Name; + var ruleArguments = property.RuleArguments; + var driftTimer = ruleArguments![0].Contains("@TimerDrift"); + + var writerMethod = driftTimer ? "WriteDeltaTime" : "Write"; + source.AppendLine($"{indent}writer.{writerMethod}({propertyName}?.Next ?? System.DateTime.MinValue);"); + } + + public void PostDeserializeMethod( + StringBuilder source, string indent, SerializableProperty property, Compilation compilation, INamedTypeSymbol classSymbol + ) + { + var deserializeTimerMethod = classSymbol + .GetMembers() + .OfType() + .FirstOrDefault( + m => + { + if (!m.ReturnsVoid || m.Parameters.Length != 1 || !m.Parameters[0].Type.IsTimeSpan(compilation)) { - if (!m.ReturnsVoid || m.Parameters.Length != 1 || !m.Parameters[0].Type.IsTimeSpan(compilation)) - { - return false; - } + return false; + } - return m.GetAttributes() - .FirstOrDefault( - attr => - { - if (!SymbolEqualityComparer.Default.Equals( + return m.GetAttributes() + .FirstOrDefault( + attr => + { + if (!SymbolEqualityComparer.Default.Equals( attr.AttributeClass, compilation.GetTypeByMetadataName( SymbolMetadata.DESERIALIZE_TIMER_FIELD_ATTRIBUTE ) )) - { - return false; - } - - var order = (int)attr.ConstructorArguments[0].Value!; - return order == property.Order; + { + return false; } - ) != null; - } - ) ?? throw new Exception("Serializing a timer requires a method with the DeserializeTimerField attribute to handle creating the timer itself."); - source.AppendLine($"{indent}{deserializeTimerMethod.Name}({property.Name}Delay);"); - } + var order = (int)attr.ConstructorArguments[0].Value!; + return order == property.Order; + } + ) != null; + } + ) ?? throw new Exception("Serializing a timer requires a method with the DeserializeTimerField attribute to handle creating the timer itself."); + + source.AppendLine($"{indent}{deserializeTimerMethod.Name}({property.Name}Delay);"); } } From 284c3d0f34c70fab470c71ef37b4ec753a9fd72b Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 28 Dec 2021 14:32:45 -0800 Subject: [PATCH 10/19] fix: Removes LINQ from Map.cs (#834) * Removes LINQ from Map * Removes broken GetObjectsInRange with items/mobile flags. --- .../Benchmarks/Benchmarks/Map/MapSelectors.cs | 665 ++++++++++++++++++ Projects/Benchmarks/Program.cs | 2 + Projects/Server/Maps/Map.cs | 233 +++--- .../Implementors/AreaCommandImplementor.cs | 9 +- .../Engines/Factions/Core/Faction.cs | 7 +- .../Explosion Potions/BaseExplosionPotion.cs | 4 +- 6 files changed, 833 insertions(+), 87 deletions(-) create mode 100644 Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs diff --git a/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs b/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs new file mode 100644 index 000000000..4c47b7189 --- /dev/null +++ b/Projects/Benchmarks/Benchmarks/Map/MapSelectors.cs @@ -0,0 +1,665 @@ +using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Jobs; +using Server; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Benchmarks +{ + [SimpleJob(RuntimeMoniker.NetCoreApp50)] + public class MapSelectors + { + static readonly Sector sector = new Sector(); + static Server.Rectangle2D bounds = new Server.Rectangle2D(0, 0, 100, 100); + + public static void Init() + { + for (int i = 0; i < 50; ++i) + { + sector.Multis.Add(new BaseMulti()); + } + for (int i = 0; i < 1000; ++i) + { + sector.BItems.Add(new BItem()); + } + for (int i = 0; i < 1000; ++i) + { + sector.Mobiles.Add(new Mobile()); + } + } + + #region MultiTiles + [Benchmark] + public void SelectMultiTilesNew() + { + foreach(StaticTile[] tiles in SelectMultiTiles(sector, bounds)) + { + for(int i = 0; i < tiles.Length; ++i) + { + int id = tiles[i].ID; + } + } + } + + [Benchmark] + public void SelectMultiTilesLinq() + { + foreach(StaticTile[] tiles in SelectMultiTilesLinq(sector, bounds)) + { + for(int i = 0; i < tiles.Length; ++i) + { + int id = tiles[i].ID; + } + } + } + + public IEnumerable SelectMultiTilesLinq(Sector s, Server.Rectangle2D bounds) + { + foreach (var o in s.Multis.Where(o => o != null && !o.Deleted)) + { + var c = o.Components; + + int x, y, xo, yo; + StaticTile[] t, r; + + for (x = bounds.Start.X; x < bounds.End.X; x++) + { + xo = x - (o.X + c.Min.X); + + if (xo < 0 || xo >= c.Width) + { + continue; + } + + for (y = bounds.Start.Y; y < bounds.End.Y; y++) + { + yo = y - (o.Y + c.Min.Y); + + if (yo < 0 || yo >= c.Height) + { + continue; + } + + t = c.Tiles[xo][yo]; + + if (t.Length <= 0) + { + continue; + } + + r = new StaticTile[t.Length]; + + for (var i = 0; i < t.Length; i++) + { + r[i] = t[i]; + r[i].Z += o.Z; + } + + yield return r; + } + } + } + } + + public IEnumerable SelectMultiTiles(Sector s, Server.Rectangle2D bounds) + { + for (int l = s.Multis.Count - 1; l >= 0; --l) + { + BaseMulti o = s.Multis[l]; + if (o != null && !o.Deleted) + { + MultiComponentList c = o.Components; + + int x, y, xo, yo; + StaticTile[] t, r; + + for (x = bounds.Start.X; x < bounds.End.X; x++) + { + xo = x - (o.X + c.Min.X); + + if (xo < 0 || xo >= c.Width) + { + continue; + } + + for (y = bounds.Start.Y; y < bounds.End.Y; y++) + { + yo = y - (o.Y + c.Min.Y); + + if (yo < 0 || yo >= c.Height) + { + continue; + } + + t = c.Tiles[xo][yo]; + + if (t.Length <= 0) + { + continue; + } + + r = new StaticTile[t.Length]; + + for (var i = 0; i < t.Length; i++) + { + r[i] = t[i]; + r[i].Z += o.Z; + } + + yield return r; + } + } + } + } + } + + #endregion + + #region Multis + [Benchmark] + public void SelectMultisNew() + { + SelectMultis(sector, bounds); + } + + [Benchmark] + public void SelectMultisLinq() + { + SelectMultisLinq(sector, bounds); + } + + public IEnumerable SelectMultisLinq(Sector s, Server.Rectangle2D bounds) + { + return s.Multis.Where(o => o != null && !o.Deleted && bounds.Contains(o.Location)); + } + + public IEnumerable SelectMultis(Sector s, Server.Rectangle2D bounds) + { + List entities = new List(s.Multis.Count); + for (int i = s.Multis.Count - 1; i >= 0; --i) + { + BaseMulti BItem = s.Multis[i]; + if (BItem != null && !BItem.Deleted && bounds.Contains(BItem.Location)) + entities.Add(BItem); + } + return entities; + } + #endregion + + #region BItems + [Benchmark] + public void SelectBItemsNew() + { + SelectBItems(sector, bounds); + } + + [Benchmark] + public void SelectBItemsLinq() + { + SelectBItemsLinq(sector, bounds); + } + + public IEnumerable SelectBItemsLinq(Sector s, Server.Rectangle2D bounds) where T : BItem + { + return s.BItems.OfType().Where(o => o != null && !o.Deleted && o.Parent == null && bounds.Contains(o.Location)); + } + + public IEnumerable SelectBItems(Sector s, Server.Rectangle2D bounds) where T : BItem + { + List entities = new List(s.BItems.Count); + Type type = typeof(T); + for (int i = s.BItems.Count - 1; i >= 0; --i) + { + BItem BItem = s.BItems[i]; + if (BItem != null && !BItem.Deleted && BItem.Parent == null && bounds.Contains(BItem.Location) && type.IsAssignableFrom(BItem.GetType())) + entities.Add(BItem as T); + } + return entities; + } + #endregion + + #region Mobiles + [Benchmark] + public void SelectMobilesNew() + { + SelectMobiles(sector, bounds); + } + + [Benchmark] + public void SelectMobilesLinq() + { + SelectMobilesLinq(sector, bounds); + } + + public IEnumerable SelectMobilesLinq(Sector s, Server.Rectangle2D bounds) where T : Mobile + { + return s.Mobiles.OfType().Where(o => o != null && !o.Deleted && bounds.Contains(o.Location)); + } + + public IEnumerable SelectMobiles(Sector s, Server.Rectangle2D bounds) where T : Mobile + { + List entities = new List(s.Mobiles.Count); + Type type = typeof(T); + for (int i = s.Mobiles.Count - 1; i >= 0; --i) + { + Mobile mob = s.Mobiles[i]; + if (mob != null && !mob.Deleted && bounds.Contains(mob.Location) && type.IsAssignableFrom(mob.GetType())) + entities.Add(mob as T); + } + return entities; + } + #endregion + + #region Entities + [Benchmark] + public void SelectEntitiesNew() + { + SelectEntities(sector, bounds); + } + + [Benchmark] + public void SelectEntitiesLinq() + { + SelectEntitiesLinq(sector, bounds); + } + + public IEnumerable SelectEntitiesLinq(Sector s, Server.Rectangle2D bounds) + { + return Enumerable.Empty() + .Union(s.Mobiles.Where(o => o != null && !o.Deleted)) + .Union(s.BItems.Where(o => o != null && !o.Deleted && o.Parent == null)) + .Where(o => bounds.Contains(o.Location)); + } + + private readonly List entities = new (10); + public IEnumerable SelectEntities(Sector s, Server.Rectangle2D bounds) + { + entities.Clear(); + entities.Capacity = s.Mobiles.Count + s.BItems.Count; + for (int i = s.Mobiles.Count - 1, j = s.BItems.Count - 1; i >= 0 || j >= 0; --i, --j) + { + if (j >= 0) + { + BItem BItem = s.BItems[j]; + if (BItem != null && !BItem.Deleted && BItem.Parent == null && bounds.Contains(BItem.Location)) + entities.Add(BItem); + } + if (i >= 0) + { + Mobile mob = s.Mobiles[i]; + if (mob != null && !mob.Deleted && bounds.Contains(mob.Location)) + entities.Add(mob); + } + } + return entities; + } + #endregion + } + public class BItem : Server.IPoint3D, IEntity + { + public object Parent { get; set; } = null; + + public bool Deleted { get; set; } = false; + + public int Z { get; set; } = 1; + + public int X { get; set; } = 1; + + public int Y { get; set; } = 1; + + public Serial Serial => throw new System.NotImplementedException(); + + public Point3D Location { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Map Map { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + + public Region Region => throw new System.NotImplementedException(); + + public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public int Hue { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Direction Direction { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public int TypeRef => throw new NotImplementedException(); + + Point3D IEntity.Location => throw new NotImplementedException(); + + Map IEntity.Map => throw new NotImplementedException(); + + int IPoint3D.Z => throw new NotImplementedException(); + + int IPoint2D.X => throw new NotImplementedException(); + + int IPoint2D.Y => throw new NotImplementedException(); + + DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + int ISerializable.TypeRef => throw new NotImplementedException(); + + Serial ISerializable.Serial => throw new NotImplementedException(); + + bool ISerializable.Deleted => throw new NotImplementedException(); + + public BItem() + { + + } + + public void Delete() + { + throw new System.NotImplementedException(); + } + + public void ProcessDelta() + { + throw new System.NotImplementedException(); + } + + public void OnStatsQuery(Server.Mobile m) + { + throw new System.NotImplementedException(); + } + + public void InvalidateProperties() + { + throw new System.NotImplementedException(); + } + + public int CompareTo(object obj) + { + throw new System.NotImplementedException(); + } + + public int CompareTo(IEntity other) + { + throw new System.NotImplementedException(); + } + + public void MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + public bool InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + public bool InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + public void RemoveBItem(BItem BItem) + { + throw new NotImplementedException(); + } + + public void BeforeSerialize() + { + throw new NotImplementedException(); + } + + public void Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + public void Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + public void SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + void IEntity.MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + void IEntity.ProcessDelta() + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + void ISerializable.BeforeSerialize() + { + throw new NotImplementedException(); + } + + void ISerializable.Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + void ISerializable.Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + void ISerializable.Delete() + { + throw new NotImplementedException(); + } + + void ISerializable.SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + public void RemoveItem(Item item) + { + throw new NotImplementedException(); + } + } + + public class Mobile : Server.IPoint3D, IEntity + { + public bool Deleted { get; set; } = false; + + public int Z { get; set; } = 1; + + public int X { get; set; } = 1; + + public int Y { get; set; } = 1; + + public Serial Serial => throw new System.NotImplementedException(); + + public Point3D Location { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Map Map { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + + public Region Region => throw new System.NotImplementedException(); + + public string Name { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public int Hue { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public Direction Direction { get => throw new System.NotImplementedException(); set => throw new System.NotImplementedException(); } + public DateTime Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + public int TypeRef => throw new NotImplementedException(); + + Point3D IEntity.Location => throw new NotImplementedException(); + + Map IEntity.Map => throw new NotImplementedException(); + + int IPoint3D.Z => throw new NotImplementedException(); + + int IPoint2D.X => throw new NotImplementedException(); + + int IPoint2D.Y => throw new NotImplementedException(); + + DateTime ISerializable.Created { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + DateTime ISerializable.LastSerialized { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + long ISerializable.SavePosition { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + BufferWriter ISerializable.SaveBuffer { get => throw new NotImplementedException(); set => throw new NotImplementedException(); } + + int ISerializable.TypeRef => throw new NotImplementedException(); + + Serial ISerializable.Serial => throw new NotImplementedException(); + + bool ISerializable.Deleted => throw new NotImplementedException(); + + public Mobile() + { + + } + + public void Delete() + { + throw new System.NotImplementedException(); + } + + public void ProcessDelta() + { + throw new System.NotImplementedException(); + } + + public void OnStatsQuery(Server.Mobile m) + { + throw new System.NotImplementedException(); + } + + public void InvalidateProperties() + { + throw new System.NotImplementedException(); + } + + public int CompareTo(object obj) + { + throw new System.NotImplementedException(); + } + + public int CompareTo(IEntity other) + { + throw new System.NotImplementedException(); + } + + public void MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + public bool InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + public bool InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + public void RemoveBItem(BItem BItem) + { + throw new NotImplementedException(); + } + + public void BeforeSerialize() + { + throw new NotImplementedException(); + } + + public void Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + public void Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + public void SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + void IEntity.MoveToWorld(Point3D location, Map map) + { + throw new NotImplementedException(); + } + + void IEntity.ProcessDelta() + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point2D p, int range) + { + throw new NotImplementedException(); + } + + bool IEntity.InRange(Point3D p, int range) + { + throw new NotImplementedException(); + } + + void ISerializable.BeforeSerialize() + { + throw new NotImplementedException(); + } + + void ISerializable.Deserialize(IGenericReader reader) + { + throw new NotImplementedException(); + } + + void ISerializable.Serialize(IGenericWriter writer) + { + throw new NotImplementedException(); + } + + void ISerializable.Delete() + { + throw new NotImplementedException(); + } + + void ISerializable.SetTypeRef(Type type) + { + throw new NotImplementedException(); + } + + public void RemoveItem(Item item) + { + throw new NotImplementedException(); + } + } + + public class BaseMulti : BItem + { + public MultiComponentList Components = MultiComponentList.Empty; + + public BaseMulti() + { + for (int i = 0; i < 20; ++i) + for (int j = 0; j < 20; ++j) + for (int z = 0; z < 20; ++z) + Components.Add(123, i, j, z); + } + + } + + public class Sector + { + public List BItems { get; set; } = new List(); + public List Mobiles { get; set; } = new List(); + public List Multis { get; set; } = new List(); + } +} diff --git a/Projects/Benchmarks/Program.cs b/Projects/Benchmarks/Program.cs index 4b5671c0f..bfdadb1bc 100644 --- a/Projects/Benchmarks/Program.cs +++ b/Projects/Benchmarks/Program.cs @@ -15,6 +15,8 @@ namespace Benchmarks // var textEncoding = BenchmarkRunner.Run(); // var logging = BenchmarkRunner.Run(); // var gumpPacket = BenchmarkRunner.Run(); + // MapSelectors.Init(); + // var mapSelectors = BenchmarkRunner.Run(); // var rngTest = BenchmarkRunner.Run(); var doubleRngText = BenchmarkRunner.Run(); } diff --git a/Projects/Server/Maps/Map.cs b/Projects/Server/Maps/Map.cs index 5593ee918..f24ca663a 100644 --- a/Projects/Server/Maps/Map.cs +++ b/Projects/Server/Maps/Map.cs @@ -1,4 +1,5 @@ using System; +using System.Buffers; using System.Collections; using System.Collections.Generic; using System.Diagnostics; @@ -54,49 +55,97 @@ namespace Server public static IEnumerable SelectClients(Sector s, Rectangle2D bounds) { - return s.Clients.Where(o => o?.Mobile?.Deleted == false && bounds.Contains(o.Mobile.Location)); + var clients = new List(s.Clients.Count); + foreach (var client in s.Clients) + { + var m = client.Mobile; + + if (m?.Deleted == false && bounds.Contains(m.Location)) + { + clients.Add(client); + } + } + + return clients; } - public static IEnumerable SelectEntities(Sector s, Rectangle2D bounds) => - SelectEntities(s, true, true, bounds); - - public static IEnumerable SelectEntities(Sector s, bool items, bool mobiles, Rectangle2D bounds) + public static IEnumerable SelectEntities(Sector s, Rectangle2D bounds) { - var eable = Enumerable.Empty(); - if (mobiles) + var entities = new List(s.Mobiles.Count + s.Items.Count); + for (int i = s.Mobiles.Count - 1, j = s.Items.Count - 1; i >= 0 || j >= 0; --i, --j) { - eable = eable.Union(s.Mobiles.Where(o => o?.Deleted == false)); - } + if (j >= 0) + { + Item item = s.Items[j]; + if (item is { Deleted: false, Parent: null } && bounds.Contains(item.Location)) + { + entities.Add(item); + } + } - if (items) - { - eable = eable.Union(s.Items.Where(o => o?.Deleted == false && o.Parent == null)); + if (i >= 0) + { + Mobile mob = s.Mobiles[i]; + if (mob is { Deleted: false } && bounds.Contains(mob.Location)) + { + entities.Add(mob); + } + } } - - return eable.Where(o => bounds.Contains(o.Location)); + return entities; } public static IEnumerable SelectMobiles(Sector s, Rectangle2D bounds) where T : Mobile { - return s.Mobiles.OfType().Where(o => !o.Deleted && bounds.Contains(o.Location)); + var entities = new List(s.Mobiles.Count); + for (int i = s.Mobiles.Count - 1; i >= 0; --i) + { + if (s.Mobiles[i] is T { Deleted: false } mob && bounds.Contains(mob.Location)) + { + entities.Add(mob); + } + } + return entities; } public static IEnumerable SelectItems(Sector s, Rectangle2D bounds) where T : Item { - return s.Items.OfType() - .Where(o => o.Deleted == false && o.Parent == null && bounds.Contains(o.Location)); + var entities = new List(s.Items.Count); + for (int i = s.Items.Count - 1; i >= 0; --i) + { + if (s.Items[i] is T { Deleted: false, Parent: null } item && bounds.Contains(item.Location)) + { + entities.Add(item); + } + } + return entities; } public static IEnumerable SelectMultis(Sector s, Rectangle2D bounds) { - return s.Multis.Where(o => o?.Deleted == false && bounds.Contains(o.Location)); + var entities = new List(s.Multis.Count); + for (int i = s.Multis.Count - 1; i >= 0; --i) + { + BaseMulti multi = s.Multis[i]; + if (multi is { Deleted: false } && bounds.Contains(multi.Location)) + { + entities.Add(multi); + } + } + return entities; } public static IEnumerable SelectMultiTiles(Sector s, Rectangle2D bounds) { - foreach (var o in s.Multis.Where(o => o?.Deleted == false)) + for (int l = s.Multis.Count - 1; l >= 0; --l) { - var c = o.Components; + BaseMulti o = s.Multis[l]; + if (o?.Deleted != false) + { + continue; + } + + MultiComponentList c = o.Components; int x, y, xo, yo; StaticTile[] t, r; @@ -143,10 +192,8 @@ namespace Server public static Map.PooledEnumerable GetClients(Map map, Rectangle2D bounds) => Map.PooledEnumerable.Instantiate(map, bounds, ClientSelector ?? SelectClients); - public static Map.PooledEnumerable GetEntities( - Map map, Rectangle2D bounds, bool items = true, - bool mobiles = true - ) => Map.PooledEnumerable.Instantiate(map, bounds, EntitySelector ?? SelectEntities); + public static Map.PooledEnumerable GetEntities(Map map, Rectangle2D bounds) => + Map.PooledEnumerable.Instantiate(map, bounds, EntitySelector ?? SelectEntities); public static Map.PooledEnumerable GetMobiles(Map map, Rectangle2D bounds) => GetMobiles(map, bounds); @@ -272,9 +319,6 @@ namespace Server public const int SectorShift = 4; public const int SectorActiveRange = 2; - private static readonly Queue> m_FixPool = new(128); - private static readonly List m_EmptyFixItems = new(); - private static ILogger _logger; private static ILogger Logger => _logger ??= LogFactory.GetLogger(typeof(Map)); @@ -389,9 +433,55 @@ namespace Server public int CompareTo(Map other) => other == null ? -1 : MapID.CompareTo(other.MapID); - public static string[] GetMapNames() => Maps.Where(m => m != null).Select(m => m.Name).ToArray(); + public static string[] GetMapNames() + { + var mapCount = 0; + for (var i = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapCount++; + } + } - public static Map[] GetMapValues() => Maps.Where(m => m != null).ToArray(); + var mapNames = new string[mapCount]; + for (int i = 0, mIndex = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapNames[mIndex++] = map.Name; + } + } + + return mapNames; + } + + public static Map[] GetMapValues() + { + var mapCount = 0; + for (var i = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapCount++; + } + } + + var mapValues = new Map[mapCount]; + for (int i = 0, mIndex = 0; i < Maps.Length; i++) + { + var map = Maps[i]; + if (map != null) + { + mapValues[mIndex++] = map; + } + } + + return mapValues; + } public static Map Parse(string value) { @@ -498,54 +588,31 @@ namespace Server public IPooledEnumerable GetMultiTilesAt(int x, int y) => PooledEnumeration.GetMultiTiles(this, new Rectangle2D(x, y, 1, 1)); - private static List AcquireFixItems(Map map, int x, int y) + private static void AcquireFixItems(Map map, int x, int y, Item[] pool, out int length) { + length = 0; if (map == null || map == Internal || x < 0 || x > map.Width || y < 0 || y > map.Height) - { - return m_EmptyFixItems; - } - - List pool = null; - - lock (m_FixPool) - { - if (m_FixPool.Count > 0) - { - pool = m_FixPool.Dequeue(); - } - } - - pool ??= new List(128); // Arbitrary limit - - var eable = map.GetItemsInRange(new Point3D(x, y, 0), 0); - - pool.AddRange( - eable.Where(item => item.ItemID <= TileData.MaxItemValue && item is not BaseMulti) - .OrderBy(item => item.Z) - .Take(pool.Capacity) - ); - - eable.Free(); - - return pool; - } - - private static void FreeFixItems(List pool) - { - if (pool == m_EmptyFixItems) { return; } - pool.Clear(); - - lock (m_FixPool) + var eable = map.GetItemsInRange(new Point3D(x, y, 0), 0); + foreach (var item in eable) { - if (m_FixPool.Count < 128) + if (item is not BaseMulti && item.ItemID <= TileData.MaxItemValue) { - m_FixPool.Enqueue(pool); + if (length == 128) + { + break; + } + + pool[length++] = item; } } + + eable.Free(); + + Array.Sort(pool, ZComparer.Default); } public void FixColumn(int x, int y) @@ -555,9 +622,10 @@ namespace Server GetAverageZ(x, y, out _, out var landAvg, out _); - var items = AcquireFixItems(this, x, y); + var items = ArrayPool.Shared.Rent(128); + AcquireFixItems(this, x, y, items, out var length); - for (var i = 0; i < items.Count; i++) + for (var i = 0; i < length; i++) { var toFix = items[i]; @@ -592,7 +660,7 @@ namespace Server } } - for (var j = 0; j < items.Count; ++j) + for (var j = 0; j < length; ++j) { if (j == i) { @@ -622,7 +690,7 @@ namespace Server } } - FreeFixItems(items); + ArrayPool.Shared.Return(items); } /* This could probably be re-implemented if necessary (perhaps via an ITile interface?). @@ -1031,15 +1099,11 @@ namespace Server public IPooledEnumerable GetObjectsInRange(Point3D p) => GetObjectsInRange(p, Core.GlobalMaxUpdateRange); - public IPooledEnumerable GetObjectsInRange(Point3D p, int range, bool items = true, bool mobiles = true) => - GetObjectsInBounds( - new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1), - items, - mobiles - ); + public IPooledEnumerable GetObjectsInRange(Point3D p, int range) => + GetObjectsInBounds(new Rectangle2D(p.m_X - range, p.m_Y - range, range * 2 + 1, range * 2 + 1)); - public IPooledEnumerable GetObjectsInBounds(Rectangle2D bounds, bool items = true, bool mobiles = true) => - PooledEnumeration.GetEntities(this, bounds, items, mobiles); + public IPooledEnumerable GetObjectsInBounds(Rectangle2D bounds) => + PooledEnumeration.GetEntities(this, bounds); public IPooledEnumerable GetClientsInRange(Point3D p) => GetClientsInRange(p, Core.GlobalMaxUpdateRange); @@ -1188,6 +1252,13 @@ namespace Server public bool CanSpawnMobile(int x, int y, int z) => Region.Find(new Point3D(x, y, z), this).AllowSpawn() && CanFit(x, y, z, 16); + private class ZComparer : IComparer + { + public static readonly ZComparer Default = new(); + + public int Compare(Item x, Item y) => x!.Z.CompareTo(y!.Z); + } + public Sector GetSector(Point3D p) => InternalGetSector(p.m_X >> SectorShift, p.m_Y >> SectorShift); public Sector GetSector(Point2D p) => InternalGetSector(p.m_X >> SectorShift, p.m_Y >> SectorShift); @@ -1529,9 +1600,7 @@ namespace Server { public static readonly NullEnumerable Instance = new(); - private readonly IEnumerable m_Empty; - - private NullEnumerable() => m_Empty = Enumerable.Empty(); + private readonly IEnumerable m_Empty = Enumerable.Empty(); IEnumerator IEnumerable.GetEnumerator() => m_Empty.GetEnumerator(); diff --git a/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs b/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs index 12a3694a1..e203e988a 100644 --- a/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs +++ b/Projects/UOContent/Commands/Generic/Implementors/AreaCommandImplementor.cs @@ -43,13 +43,18 @@ namespace Server.Commands.Generic return; } - var eable = map.GetObjectsInBounds(rect, items, mobiles); + var eable = map.GetObjectsInBounds(rect); var objs = new List(); foreach (var obj in eable) { - if ((!mobiles || obj is not Mobile || BaseCommand.IsAccessible(from, obj)) && ext.IsValid(obj)) + if (!mobiles && obj is Mobile || !items && obj is Item) + { + continue; + } + + if (BaseCommand.IsAccessible(from, obj) && ext.IsValid(obj)) { objs.Add(obj); } diff --git a/Projects/UOContent/Engines/Factions/Core/Faction.cs b/Projects/UOContent/Engines/Factions/Core/Faction.cs index 43d67c6ca..9345a7328 100644 --- a/Projects/UOContent/Engines/Factions/Core/Faction.cs +++ b/Projects/UOContent/Engines/Factions/Core/Faction.cs @@ -273,9 +273,14 @@ namespace Server.Factions return false; } - var eable = mob.Map.GetObjectsInRange(mob.Location, range, items, mobs); + var eable = mob.Map.GetObjectsInRange(mob.Location, range); foreach (var obj in eable) { + if (!mobs && obj is Mobile || !items && obj is Item) + { + continue; + } + if (type.IsInstanceOfType(obj)) { eable.Free(); diff --git a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs index 01de15b12..a08b6a557 100644 --- a/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs +++ b/Projects/UOContent/Items/Skill Items/Magical/Potions/Explosion Potions/BaseExplosionPotion.cs @@ -215,7 +215,7 @@ namespace Server.Items alchemyBonus = (int)(from.Skills.Alchemy.Value / (Core.AOS ? 5 : 10)); } - var eable = map.GetObjectsInRange(loc, ExplosionRange, LeveledExplosion); + var eable = map.GetObjectsInRange(loc, ExplosionRange); using var queue = PooledRefQueue.Create(); var toDamage = 0; @@ -234,7 +234,7 @@ namespace Server.Items queue.Enqueue(entity); } } - else if (entity is BaseExplosionPotion) + else if (LeveledExplosion && entity is BaseExplosionPotion) { queue.Enqueue(entity); } From 529fd90005dcab2f3fd8663df3f0c5cebfba375f Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Tue, 28 Dec 2021 19:00:16 -0800 Subject: [PATCH 11/19] chore: Cleanup enchanted sextant (#904) --- .../Quests/Core/Items/EnchantedSextant.cs | 54 +++++-------------- 1 file changed, 14 insertions(+), 40 deletions(-) diff --git a/Projects/UOContent/Engines/Quests/Core/Items/EnchantedSextant.cs b/Projects/UOContent/Engines/Quests/Core/Items/EnchantedSextant.cs index b671b2960..e30038aed 100644 --- a/Projects/UOContent/Engines/Quests/Core/Items/EnchantedSextant.cs +++ b/Projects/UOContent/Engines/Quests/Core/Items/EnchantedSextant.cs @@ -102,14 +102,8 @@ namespace Server.Items banks = m_IlshenarBanks; moongates = PMList.Ilshenar; #else - from.NetState.SendMessageLocalized( - Serial, - ItemID, - MessageType.Label, - 0x482, - 3, - 1061684 - ); // The magic of the sextant fails... + // The magic of the sextant fails... + from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, 1061684); return; #endif @@ -155,43 +149,23 @@ namespace Server.Items } } - int moonMsg; - if (moongateDistance == double.MaxValue) + int moonMsg = moongateDistance switch { - moonMsg = 1048021; // The sextant fails to find a Moongate nearby. - } - else if (moongateDistance > m_LongDistance) - { - moonMsg = 1046449 + (int)from.GetDirectionTo(closestMoongate); // A moongate is * from here - } - else if (moongateDistance > m_ShortDistance) - { - moonMsg = 1048010 + (int)from.GetDirectionTo(closestMoongate); // There is a Moongate * of here. - } - else - { - moonMsg = 1048018; // You are next to a Moongate at the moment. - } + double.MaxValue => 1048021, // The sextant fails to find a Moongate nearby. + > m_LongDistance => 1046449 + (int)from.GetDirectionTo(closestMoongate), // A moongate is * from here + > m_ShortDistance => 1048010 + (int)from.GetDirectionTo(closestMoongate), // There is a Moongate * of here. + _ => 1048018 // You are next to a Moongate at the moment. + }; from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Label, 0x482, 3, moonMsg); - int bankMsg; - if (bankDistance == double.MaxValue) + int bankMsg = bankDistance switch { - bankMsg = 1048020; // The sextant fails to find a Bank nearby. - } - else if (bankDistance > m_LongDistance) - { - bankMsg = 1046462 + (int)from.GetDirectionTo(closestBank); // A town is * from here - } - else if (bankDistance > m_ShortDistance) - { - bankMsg = 1048002 + (int)from.GetDirectionTo(closestBank); // There is a city Bank * of here. - } - else - { - bankMsg = 1048019; // You are next to a Bank at the moment. - } + double.MaxValue => 1048020, // The sextant fails to find a Bank nearby. + > m_LongDistance => 1046462 + (int)from.GetDirectionTo(closestBank), // A town is * from here + > m_ShortDistance => 1048002 + (int)from.GetDirectionTo(closestBank), // There is a city Bank * of here. + _ => 1048019 // You are next to a Bank at the moment. + }; from.NetState.SendMessageLocalized(Serial, ItemID, MessageType.Label, 0x5AA, 3, bankMsg); } From c1134c526fb91c2987ed7e8e973ab8d8bd4ea8fa Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 29 Dec 2021 10:10:53 -0800 Subject: [PATCH 12/19] fix: Fixes sorting (#905) --- Projects/Server/Maps/Map.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Projects/Server/Maps/Map.cs b/Projects/Server/Maps/Map.cs index f24ca663a..7f5e87d1f 100644 --- a/Projects/Server/Maps/Map.cs +++ b/Projects/Server/Maps/Map.cs @@ -612,7 +612,7 @@ namespace Server eable.Free(); - Array.Sort(pool, ZComparer.Default); + Array.Sort(pool, 0, length, ZComparer.Default); } public void FixColumn(int x, int y) From 752407d6f4ffcca49638959c47f1551c93096116 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Wed, 29 Dec 2021 10:18:27 -0800 Subject: [PATCH 13/19] fix: Fixes guild roster crash (#906) --- .../Gumps/Guilds/New Guild System/BaseGuildListGump.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildListGump.cs b/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildListGump.cs index 8b09c06b2..f157ea4c9 100644 --- a/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildListGump.cs +++ b/Projects/UOContent/Gumps/Guilds/New Guild System/BaseGuildListGump.cs @@ -31,7 +31,7 @@ namespace Server.Guilds m_List = list; } - public virtual bool WillFilter => m_Filter.Length >= 0; + public virtual bool WillFilter => m_Filter.Length > 0; public override void PopulateGump() { @@ -55,7 +55,7 @@ namespace Server.Guilds } m_List.Sort(m_Comparer); - m_StartNumber = Math.Clamp(m_StartNumber, 0, m_List.Count - 1); + m_StartNumber = Math.Max(Math.Min(m_StartNumber, m_List.Count - 1), 0); AddBackground(130, 75, 385, 30, 0xBB8); AddTextEntry(135, 80, 375, 30, 0x481, 1, m_Filter); @@ -109,8 +109,8 @@ namespace Server.Guilds else // descending, go from bottom of list to the top { for (var i = m_List.Count - 1 - m_StartNumber; - i >= 0 && i >= m_List.Count - itemsPerPage - m_StartNumber; - i--) + i >= 0 && i >= m_List.Count - itemsPerPage - m_StartNumber; + i--) { DrawEntry(m_List[i], i, itemNumber++); } From ba378fc5f279b71d91e2ebf6993f236dbc93480b Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 14:19:39 -0800 Subject: [PATCH 14/19] fix: Adds Ubuntu 14 and Linux Mint 17/18/19 support specifically (#908) --- Directory.Build.props | 2 +- Projects/Server.Tests/Server.Tests.csproj | 2 +- Projects/Server/Server.csproj | 2 +- Projects/UOContent/UOContent.csproj | 8 ++++---- publish.cmd | 16 +++++++++++----- 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Directory.Build.props b/Directory.Build.props index be723978b..d0e008643 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -11,7 +11,7 @@ true true NU1603 - win-x64;debian.10-x64;debian.11-x64;ubuntu.16.04-x64;ubuntu.18.04-x64;ubuntu.20.04-x64;centos.7-x64;centos.8-x64;fedora.32-x64;fedora.33-x64;fedora.34-x64;rhel.7-x64;rhel.8-x64;osx-x64 + win-x64;debian.10-x64;debian.11-x64;ubuntu.16.04-x64;ubuntu.18.04-x64;ubuntu.20.04-x64;centos.7-x64;centos.8-x64;fedora.32-x64;fedora.33-x64;fedora.34-x64;rhel.7-x64;rhel.8-x64;linuxmint.17-x64;linuxmint.18-x64;linuxmint.19-x64;osx-x64 Debug;Release;Analyze false true diff --git a/Projects/Server.Tests/Server.Tests.csproj b/Projects/Server.Tests/Server.Tests.csproj index 6536e8cab..b33bf4c7d 100644 --- a/Projects/Server.Tests/Server.Tests.csproj +++ b/Projects/Server.Tests/Server.Tests.csproj @@ -7,7 +7,7 @@ - + diff --git a/Projects/Server/Server.csproj b/Projects/Server/Server.csproj index 392fccc6f..5293d55e6 100755 --- a/Projects/Server/Server.csproj +++ b/Projects/Server/Server.csproj @@ -36,7 +36,7 @@ - + diff --git a/Projects/UOContent/UOContent.csproj b/Projects/UOContent/UOContent.csproj index 06e297a52..f260b9a4c 100755 --- a/Projects/UOContent/UOContent.csproj +++ b/Projects/UOContent/UOContent.csproj @@ -38,12 +38,12 @@ false - + - - - + + + diff --git a/publish.cmd b/publish.cmd index e0f9fe6df..0490b16a8 100755 --- a/publish.cmd +++ b/publish.cmd @@ -12,7 +12,7 @@ elif [[ $(uname) = "Darwin" ]]; then os="-r osx-x64" elif [[ -f /etc/os-release ]]; then . /etc/os-release - NAME="$(tr '[:upper:]' '[:lower:]' <<< $NAME)" + NAME="$(tr '[:upper:]' '[:lower:]' <<< $NAME | tr -d [:blank:])" os="-r $NAME.$VERSION_ID-x64" fi @@ -32,8 +32,11 @@ dotnet clean --verbosity quiet echo dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json -echo dotnet publish ${config} ${os} --framework net6.0 --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj -dotnet publish ${config} ${os} --framework net6.0 --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj +echo dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj +dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj + +echo dotnet publish ${config} ${os} --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj +dotnet publish ${config} ${os} --no-restore --self-contained=false -o Distribution/Assemblies Projects/UOContent/UOContent.csproj echo dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj @@ -65,8 +68,11 @@ dotnet clean --verbosity quiet echo dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json dotnet restore --force-evaluate --source https://api.nuget.org/v3/index.json -echo dotnet publish %config% %os% --framework net6.0 --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj -dotnet publish %config% %os% --framework net6.0 --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj +echo dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj +dotnet build -c Release Projects/SerializationGenerator/SerializationGenerator.csproj + +echo dotnet publish %config% %os% --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj +dotnet publish %config% %os% --no-restore --self-contained=false -o Distribution\Assemblies Projects\UOContent\UOContent.csproj echo dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj dotnet build -c Release Projects/SerializationSchemaGenerator/SerializationSchemaGenerator.csproj From 4fd8b4d30749509999d510eed207e62405601478 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 14:22:58 -0800 Subject: [PATCH 15/19] fix: Fixes crash from bad input in TC (#909) --- Projects/UOContent/Special Systems/Engines/TestCenter.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Projects/UOContent/Special Systems/Engines/TestCenter.cs b/Projects/UOContent/Special Systems/Engines/TestCenter.cs index 2c84bc177..d8d2505e4 100644 --- a/Projects/UOContent/Special Systems/Engines/TestCenter.cs +++ b/Projects/UOContent/Special Systems/Engines/TestCenter.cs @@ -52,10 +52,10 @@ namespace Server.Misc return; } - var value = double.Parse(valueStr); - try { + var value = double.Parse(valueStr); + if (name.InsensitiveEquals("str")) { ChangeStrength(from, (int)value); From 573ddfa27b5fa4ac301261dc351e7c0afe33a820 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 19:05:28 -0800 Subject: [PATCH 16/19] docs: Updates installation docs for the main site. (#911) --- README.md | 11 ++++++++--- docs/assets/stylesheets/extra.css | 4 ++++ docs/building-server.md | 4 +++- docs/installation.md | 6 +++--- docs/overrides/.icons/brands/linuxmint.svg | 1 + docs/quick-start.md | 17 +++++++++++------ 6 files changed, 30 insertions(+), 13 deletions(-) create mode 100644 docs/overrides/.icons/brands/linuxmint.svg diff --git a/README.md b/README.md index 87a102ff7..0983a8826 100644 --- a/README.md +++ b/README.md @@ -19,16 +19,17 @@ ModernUO [![Discord](https://img.shields.io/discord/751317910504603701?logo=disc ![MacOS 10.15/11/12](https://img.shields.io/badge/-monterey-222222?logo=apple&logoColor=white) [![Debian 10/11](https://img.shields.io/badge/-bullseye-A81D33?logo=debian)](https://www.debian.org/distrib/) [![Ubuntu 16/18/20 LTS](https://img.shields.io/badge/-20LTS-E95420?logo=ubuntu&logoColor=white)](https://ubuntu.com/download/server) +[![Linux Mint 17/18/19/20](https://img.shields.io/badge/-20-87CF3E?logo=linux%20mint&logoColor=white)](https://linuxmint.com/download.php) [![CentOS 7/8](https://img.shields.io/badge/-8.5-262577?logo=centos&logoColor=white)](https://www.centos.org/download/) [![Fedora 32/33/34](https://img.shields.io/badge/-fedora%2034-0B57A4)](https://getfedora.org/en/server/download/) [![RedHat 7/8](https://img.shields.io/badge/-8-BE0000?logo=red%20hat&logoColor=white)](https://access.redhat.com/downloads) #### Running the server -[![.NET](https://img.shields.io/badge/.NET-%206.0-5C2D91)](https://dotnet.microsoft.com/download/dotnet/6.0) +[![.NET](https://img.shields.io/badge/-6.0-5C2D91?logo=.NET)](https://dotnet.microsoft.com/download/dotnet/6.0) #### Development [![git](https://img.shields.io/badge/-git-F05032?logo=git&logoColor=white)](https://git-scm.com/downloads) -[![.NET](https://img.shields.io/badge/.NET-%206.0%20SDK-5C2D91)](https://dotnet.microsoft.com/download/dotnet/6.0) +[![.NET](https://img.shields.io/badge/-%206.0%20SDK-5C2D91?logo=.NET)](https://dotnet.microsoft.com/download/dotnet/6.0) #### Supported IDEs     @@ -51,11 +52,12 @@ Rider 2021.3+           & - `win` - Windows 10/11/2016/2019/2022 - `osx` - MacOS 10.15/11.0+/12.0+ (Catalina, Big Sur, Monterey) - `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04` - Ubuntu LTS + - `linuxmint.17`, `linuxmint.18`, `linuxmint.19` - Linux Mint - `debian.10`, `debian.11` - Debian - `centos.7`, `centos.8` - CentOS - `fedora.32`, `fedora.33`, `fedora.34` - Fedora - `rhel.7`, `rhel.8` - Redhat - - If blank, the operating system running the build is used + - If blank, the operating system running the build is used. Linux Mint 20 is not supported directly yet, so build explicitly against `ubuntu.20.04` instead. **Note:** Building in Visual Studio (or Rider) will not run the schema migration. The schema migration ensures future changes to the code will be backward compatible. @@ -64,6 +66,9 @@ to the code will be backward compatible. - Follow the [publish](https://github.com/modernuo/ModernUO#publishing-builds) instructions - Run `ModernUO.exe` or `dotnet ModernUO.dll` from the `Distribution` directory on the server +**Note:** If you are running a version of linux that isn't listed above, then you may have to install the following using a package manager: + * `libargon2-dev`, `libz-dev`, and `zstd` + ## Thanks - RunUO Team & Community - ServUO Team & Community diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css index 361f284ce..73389904f 100644 --- a/docs/assets/stylesheets/extra.css +++ b/docs/assets/stylesheets/extra.css @@ -82,6 +82,10 @@ html .md-footer-meta.md-typeset a:hover { color: #e95420; } +.linuxmint { + color: #87CF3E; +} + .debian { color: #d70a53; } diff --git a/docs/building-server.md b/docs/building-server.md index b167e1c6a..232f1f930 100644 --- a/docs/building-server.md +++ b/docs/building-server.md @@ -23,6 +23,8 @@ The operating system to build the server against. If not specified then the serv :fontawesome-brands-windows:{: .windows } `win`
:fontawesome-brands-apple:{: .apple } `osx`
-:fontawesome-brands-ubuntu:{: .ubuntu } `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04`
+:fontawesome-brands-ubuntu:{: .ubuntu } `ubuntu.14.04` `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04`
+:brands-linuxmint:{: .linuxmint } `linuxmint.17` `linuxmint.18`, `linuxmint.19`
:brands-debian:{: .debian } `debian.9`, `debian.10`
:fontawesome-brands-centos:{: .centos } `centos.7`, `centos.8` +:fontawesome-brands-redhat:{: .redhat } `redhat.7`, `redhat.8` diff --git a/docs/installation.md b/docs/installation.md index a6bd079ec..6fcb6d794 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -6,7 +6,7 @@ title: Installation === "Windows" ### Prerequisites - 1. Download and install the latest [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) + 1. Download and install the latest [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) 1. Download and install from [here](https://git-scm.com/download/win) !!! Tip @@ -22,7 +22,7 @@ title: Installation === "OSX"

Prerequisites

- 1. Download and install the latest [.NET 5 SDK](https://dotnet.microsoft.com/download/dotnet/5.0) + 1. Download and install the latest [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) 1. Using _terminal_, install [homebrew](https://brew.sh) and git: ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" @@ -37,7 +37,7 @@ title: Installation === "Linux"

Prerequisites

- 1. Download and install the latest [.NET Core SDK](instructions [here](https://docs.microsoft.com/en-us/dotnet/core/install/linux)) + 1. Download and install the latest [.NET 6 SDK](instructions [here](https://docs.microsoft.com/en-us/dotnet/core/install/linux)) 1. Using _bash_, install git: ```bash sudo apt update && sudo apt install git diff --git a/docs/overrides/.icons/brands/linuxmint.svg b/docs/overrides/.icons/brands/linuxmint.svg new file mode 100644 index 000000000..a9dcf1131 --- /dev/null +++ b/docs/overrides/.icons/brands/linuxmint.svg @@ -0,0 +1 @@ +Linux Mint \ No newline at end of file diff --git a/docs/quick-start.md b/docs/quick-start.md index 189b4841e..bd14b4f75 100644 --- a/docs/quick-start.md +++ b/docs/quick-start.md @@ -7,20 +7,25 @@ title: Quick Start If you are familiar with RunUO, then follow these steps to get your ModernUO server running in less than 10 minutes: === "Windows" - 1. Download and install the [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/5.0) - 1. Download and extract [ModernUO](https://github.com/modernuo/ModernUO/releases/latest) to a folder. + 1. Download and install the [.NET 6 Runtime](https://dotnet.microsoft.com/download/dotnet/6.0) + 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. + 1. Run publish.cmd 1. Navigate to the _Distribution_ folder. 1. Run `ModernUO.exe` === "OSX" - 1. Download and install the [.NET 5 Runtime](https://dotnet.microsoft.com/download/dotnet/5.0) - 1. Download and extract [ModernUO](https://github.com/modernuo/ModernUO/releases/latest) to a folder. + 1. Download and install the [.NET 6 Runtime](https://dotnet.microsoft.com/download/dotnet/6.0) + 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. + 1. Using _terminal_, navigate to the _ModernUO_ folder. + 1. Run `./publish.cmd` 1. Using _terminal_, navigate to the _Distribution_ folder. 1. Run `dotnet ModernUO.dll` === "Linux" - 1. Download and install the [.NET 5 Runtime](instructions [here](https://docs.microsoft.com/en-us/dotnet/core/install/linux)) - 1. Download and extract [ModernUO](https://github.com/modernuo/ModernUO/releases/latest) to a folder. + 1. Download and install the [.NET 6 Runtime](https://docs.microsoft.com/en-us/dotnet/core/install/linux) + 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. + 1. Using _bash_, navigate to the _ModernUO_ folder. + 1. Run `./publish.cmd` 1. Using _bash_, navigate to the _Distribution_ folder. 1. Run `dotnet ModernUO.dll` From 08df0307e58fe7fe1e8a8a0cfa11fcc92625b634 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 19:08:50 -0800 Subject: [PATCH 17/19] docs: Adds workflow dispatch --- .github/workflows/update-docs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/update-docs.yml b/.github/workflows/update-docs.yml index ccd2c2280..62b080225 100644 --- a/.github/workflows/update-docs.yml +++ b/.github/workflows/update-docs.yml @@ -3,6 +3,7 @@ name: Updates Docs on: repository_dispatch: types: [docs] + workflow_dispatch: jobs: update-docs: From 24c683870d24ddf50dd23041c1f1b68af2f9c181 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 22:10:29 -0800 Subject: [PATCH 18/19] docs: Updates markdown docs (#912) --- docs/assets/stylesheets/extra.css | 10 +++++++++- docs/building-server.md | 5 +++-- docs/installation.md | 12 +++++------ docs/quick-start.md | 33 ------------------------------- mkdocs.yml | 7 ++++--- 5 files changed, 22 insertions(+), 45 deletions(-) delete mode 100644 docs/quick-start.md diff --git a/docs/assets/stylesheets/extra.css b/docs/assets/stylesheets/extra.css index 73389904f..dfe2e4d38 100644 --- a/docs/assets/stylesheets/extra.css +++ b/docs/assets/stylesheets/extra.css @@ -83,17 +83,25 @@ html .md-footer-meta.md-typeset a:hover { } .linuxmint { - color: #87CF3E; + color: #87cF3e; } .debian { color: #d70a53; } +.fedora { + color: #3c6eb4; +} + .centos { color: #212078; } +.redhat { + color: #be0000; +} + .codehilitetable .linenodiv pre, .highlighttable .linenodiv pre { color: var(--md-default-bg-color); } diff --git a/docs/building-server.md b/docs/building-server.md index 232f1f930..9e2e63b71 100644 --- a/docs/building-server.md +++ b/docs/building-server.md @@ -24,7 +24,8 @@ The operating system to build the server against. If not specified then the serv :fontawesome-brands-windows:{: .windows } `win`
:fontawesome-brands-apple:{: .apple } `osx`
:fontawesome-brands-ubuntu:{: .ubuntu } `ubuntu.14.04` `ubuntu.16.04`, `ubuntu.18.04` `ubuntu.20.04`
-:brands-linuxmint:{: .linuxmint } `linuxmint.17` `linuxmint.18`, `linuxmint.19`
+:brands-linuxmint:{: .linuxmint } `linuxmint.17` `linuxmint.18`, `linuxmint.19`, `ubuntu.20.04` for v20
:brands-debian:{: .debian } `debian.9`, `debian.10`
-:fontawesome-brands-centos:{: .centos } `centos.7`, `centos.8` +:fontawesome-brands-fedora:{: .fedora } `fedora.32`, `fedora.33`, `fedora.34`
+:fontawesome-brands-centos:{: .centos } `centos.7`, `centos.8`
:fontawesome-brands-redhat:{: .redhat } `redhat.7`, `redhat.8` diff --git a/docs/installation.md b/docs/installation.md index 6fcb6d794..edf4c673b 100644 --- a/docs/installation.md +++ b/docs/installation.md @@ -21,14 +21,14 @@ title: Installation ``` === "OSX" -

Prerequisites

- 1. Download and install the latest [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) + ### Prerequisites + 1. Download and install the latest [.NET 6 SDK](https://dotnet.microsoft.com/download/dotnet/6.0). 1. Using _terminal_, install [homebrew](https://brew.sh) and git: ```bash /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" brew install git ``` -

Install ModernUO

+ ### Install ModernUO 1. Using _terminal_, navigate to the folder where you want to install ModernUO and run: ```bash git clone https://github.com/modernuo/modernuo @@ -36,8 +36,8 @@ title: Installation ``` === "Linux" -

Prerequisites

- 1. Download and install the latest [.NET 6 SDK](instructions [here](https://docs.microsoft.com/en-us/dotnet/core/install/linux)) + ### Prerequisites + 1. Download and install the latest [.NET 6 SDK](https://docs.microsoft.com/en-us/dotnet/core/install/linux). 1. Using _bash_, install git: ```bash sudo apt update && sudo apt install git @@ -46,7 +46,7 @@ title: Installation !!! Note The command to install git might be different for your flavor of linux. Consult your local Google search for answers. -

Install ModernUO

+ ### Install ModernUO 1. Using _bash_, navigate to the folder where you want to install ModernUO and run: ```bash git clone https://github.com/modernuo/modernuo diff --git a/docs/quick-start.md b/docs/quick-start.md deleted file mode 100644 index bd14b4f75..000000000 --- a/docs/quick-start.md +++ /dev/null @@ -1,33 +0,0 @@ ---- -title: Quick Start ---- - -# Quick Start - -If you are familiar with RunUO, then follow these steps to get your ModernUO server running in less than 10 minutes: - -=== "Windows" - 1. Download and install the [.NET 6 Runtime](https://dotnet.microsoft.com/download/dotnet/6.0) - 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. - 1. Run publish.cmd - 1. Navigate to the _Distribution_ folder. - 1. Run `ModernUO.exe` - -=== "OSX" - 1. Download and install the [.NET 6 Runtime](https://dotnet.microsoft.com/download/dotnet/6.0) - 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. - 1. Using _terminal_, navigate to the _ModernUO_ folder. - 1. Run `./publish.cmd` - 1. Using _terminal_, navigate to the _Distribution_ folder. - 1. Run `dotnet ModernUO.dll` - -=== "Linux" - 1. Download and install the [.NET 6 Runtime](https://docs.microsoft.com/en-us/dotnet/core/install/linux) - 1. Using [git](https://git-scm.com/downloads), clone the ModernUO repository to a folder. - 1. Using _bash_, navigate to the _ModernUO_ folder. - 1. Run `./publish.cmd` - 1. Using _bash_, navigate to the _Distribution_ folder. - 1. Run `dotnet ModernUO.dll` - -!!! Note - Follow the rest of the [Get Started](../installation) guide to learn how to connect, configure, and customize, your server. diff --git a/mkdocs.yml b/mkdocs.yml index d0dbbf9f4..58cee9c59 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -41,14 +41,16 @@ markdown_extensions: - admonition - footnotes - meta - - markdown.extensions.toc: + - toc: + toc_depth: "1-1" permalink: true - attr_list - pymdownx.highlight - pymdownx.inlinehilite - pymdownx.superfences - pymdownx.snippets - - pymdownx.tabbed + - pymdownx.tabbed: + alternate_style: true - pymdownx.caret - pymdownx.mark - pymdownx.tilde @@ -67,6 +69,5 @@ markdown_extensions: nav: - Home: 'index.md' - 'Get Started': - - 'quick-start.md' - 'installation.md' - 'building-server.md' From 2f13dfebedc146ad7a108fcdc7521f17722f0741 Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Mon, 3 Jan 2022 22:16:56 -0800 Subject: [PATCH 19/19] docs: Fixes edit uri for docs (#913) --- mkdocs.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/mkdocs.yml b/mkdocs.yml index 58cee9c59..dcb2d826d 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -3,6 +3,7 @@ site_name: ModernUO site_author: Kamron Batman site_url: https://modernuo.com +edit_uri: edit/main/docs/ # Repository repo_name: modernuo/modernuo