From 038c3be2580286924c0d3fa895c85b3384e5709d Mon Sep 17 00:00:00 2001 From: Kamron Batman <3953314+kamronbatman@users.noreply.github.com> Date: Sun, 12 Apr 2020 21:33:24 -0700 Subject: [PATCH] Adds BufferReader and BufferWriter. Updates UOP handling. (#101) --- Projects/Scripts/Accounting/Account.cs | 18 +- Projects/Scripts/Accounting/AccountHandler.cs | 5 +- Projects/Scripts/Accounting/Accounts.cs | 2 +- Projects/Scripts/Commands/Dupe.cs | 2 +- Projects/Scripts/Commands/VisibilityList.cs | 8 +- Projects/Scripts/Engines/Chat/Chatold.cs | 8 +- .../Scripts/Engines/ConPVP/DuelContext.cs | 34 +- .../Doom/LeverPuzzle/LeverPuzzleRegions.cs | 3 +- .../Scripts/Engines/Factions/Core/Faction.cs | 28 +- .../Scripts/Engines/Factions/Core/Keywords.cs | 2 +- Projects/Scripts/Engines/Help/HelpGump.cs | 15 +- .../Scripts/Engines/MLQuests/MLQuestSystem.cs | 4 +- Projects/Scripts/Engines/Party/Party.cs | 9 +- .../Scripts/Engines/Plants/PlantSystem.cs | 6 +- .../Engines/VeteranRewards/RewardSystem.cs | 24 +- .../Scripts/Engines/Virtues/VirtueGump.cs | 36 +- Projects/Scripts/Gumps/ReportMurderer.cs | 6 +- .../Halloween/2006/Engines/TrickOrTreat.cs | 2 +- .../Halloween/2012/Engines/PlayerZombies.cs | 6 +- .../Items/Construction/Doors/BaseDoor.cs | 99 +- Projects/Scripts/Items/Food/Beverage.cs | 4 +- Projects/Scripts/Items/Misc/Corpses/Corpse.cs | 11 +- Projects/Scripts/Items/Misc/Teleporter.cs | 4 +- .../Items/Skill Items/Magical/Spellbook.cs | 36 +- .../Scripts/Items/Skill Items/Misc/Bandage.cs | 35 +- .../Items/Weapons/Abilities/WeaponAbility.cs | 8 +- Projects/Scripts/Items/Weapons/Fists.cs | 8 +- Projects/Scripts/Misc/Animations.cs | 26 +- Projects/Scripts/Misc/AttackMessage.cs | 2 +- Projects/Scripts/Misc/Broadcasts.cs | 24 +- Projects/Scripts/Misc/BuffIcons.cs | 14 +- Projects/Scripts/Misc/CharacterCreation.cs | 2 +- Projects/Scripts/Misc/ClientVerification.cs | 6 +- Projects/Scripts/Misc/CrashGuard.cs | 18 +- Projects/Scripts/Misc/Fastwalk.cs | 4 +- Projects/Scripts/Misc/Guild.cs | 10 +- Projects/Scripts/Misc/Keywords.cs | 4 +- Projects/Scripts/Misc/LightCycle.cs | 4 +- Projects/Scripts/Misc/LoginStats.cs | 6 +- Projects/Scripts/Misc/Paperdoll.cs | 9 +- Projects/Scripts/Misc/ProfanityProtection.cs | 4 +- Projects/Scripts/Misc/Profile.cs | 24 +- Projects/Scripts/Misc/RenameRequests.cs | 10 +- Projects/Scripts/Misc/ShardPoller.cs | 4 +- Projects/Scripts/Misc/WeightOverloading.cs | 4 +- Projects/Scripts/Mobiles/AI/MageAI.cs | 2 +- Projects/Scripts/Mobiles/AI/ThiefAI.cs | 2 +- .../Humanoid/Melee/KhaldunRevenant.cs | 14 +- Projects/Scripts/Mobiles/PlayerMobile.cs | 89 +- Projects/Scripts/Multis/Boats/BaseBoat.cs | 2 +- Projects/Scripts/Multis/Boats/Strandedness.cs | 8 +- Projects/Scripts/Multis/HouseFoundation.cs | 4 +- Projects/Scripts/Regions/HouseRegion.cs | 8 +- Projects/Scripts/Scripts.csproj | 2 +- .../SpecialSystems/Engines/GiftGiving.cs | 6 +- .../SpecialSystems/Engines/PreventInaccess.cs | 4 +- .../Spells/Mysticism/SpellPlagueSpell.cs | 4 +- .../Spells/Mysticism/StoneFormSpell.cs | 4 +- .../Scripts/Spells/Ninjitsu/AnimalForm.cs | 6 +- .../Spells/Spellweaving/EtherealVoyage.cs | 12 +- .../Scripts/Spells/Spellweaving/GiftOfLife.cs | 6 +- .../Scripts/Spells/Spellweaving/ReaperForm.cs | 6 +- Projects/Server/AssemblyHandler.cs | 23 +- Projects/Server/Buffers/BufferReader.cs | 314 +++++ .../Server/Buffers/BufferReaderExtensions.cs | 181 +++ Projects/Server/Buffers/BufferWriter.cs | 143 +++ .../Server/Buffers/DiagnosticMemoryPool.cs | 132 -- .../Server/Buffers/DiagnosticPoolBlock.cs | 188 --- .../Server/Buffers/MemoryPoolThrowHelper.cs | 56 +- Projects/Server/Commands.cs | 6 + Projects/Server/EventSink.cs | 1086 ----------------- Projects/Server/Events/AccountLoginEvent.cs | 52 + .../Server/Events/AggressiveActionEvent.cs | 75 ++ .../Server/Events/CharacterCreatedEvent.cs | 110 ++ Projects/Server/Events/CreateGuildEvent.cs | 41 + Projects/Server/Events/EventSink.cs | 150 +++ Projects/Server/Events/FastwalkEvent.cs | 45 + Projects/Server/Events/GameLoginEvent.cs | 52 + Projects/Server/Events/MovementEvent.cs | 74 ++ Projects/Server/Events/ServerCrashedEvent.cs | 40 + Projects/Server/Events/ServerListEvent.cs | 63 + .../Server/Events/SocketConnectionEvent.cs | 45 + Projects/Server/Events/SpeechEvent.cs | 46 + Projects/Server/Main.cs | 6 +- Projects/Server/Mobile.cs | 33 +- Projects/Server/MultiData.cs | 350 +++++- Projects/Server/Network/MessagePumpService.cs | 40 +- Projects/Server/Network/NetState.cs | 3 +- Projects/Server/Network/PacketHandlers.cs | 96 +- ...nHandler.cs => ServerConnectionHandler.cs} | 21 + Projects/Server/Network/ServerStartup.cs | 22 +- Projects/Server/Network/TcpServer.cs | 21 + .../Persistence/StandardSaveStrategy.cs | 12 +- Projects/Server/TileData.cs | 216 ++-- Projects/Server/TileMatrix.cs | 98 +- .../Server/Utilities/Xoshiro256PlusPlus.cs | 2 - Projects/Server/World.cs | 2 +- THIRD-PARTY-NOTICES | 22 + 98 files changed, 2458 insertions(+), 2185 deletions(-) create mode 100644 Projects/Server/Buffers/BufferReader.cs create mode 100644 Projects/Server/Buffers/BufferReaderExtensions.cs create mode 100644 Projects/Server/Buffers/BufferWriter.cs delete mode 100644 Projects/Server/Buffers/DiagnosticMemoryPool.cs delete mode 100644 Projects/Server/Buffers/DiagnosticPoolBlock.cs delete mode 100644 Projects/Server/EventSink.cs create mode 100644 Projects/Server/Events/AccountLoginEvent.cs create mode 100644 Projects/Server/Events/AggressiveActionEvent.cs create mode 100644 Projects/Server/Events/CharacterCreatedEvent.cs create mode 100644 Projects/Server/Events/CreateGuildEvent.cs create mode 100644 Projects/Server/Events/EventSink.cs create mode 100644 Projects/Server/Events/FastwalkEvent.cs create mode 100644 Projects/Server/Events/GameLoginEvent.cs create mode 100644 Projects/Server/Events/MovementEvent.cs create mode 100644 Projects/Server/Events/ServerCrashedEvent.cs create mode 100644 Projects/Server/Events/ServerListEvent.cs create mode 100644 Projects/Server/Events/SocketConnectionEvent.cs create mode 100644 Projects/Server/Events/SpeechEvent.cs rename Projects/Server/Network/{UOConnectionHandler.cs => ServerConnectionHandler.cs} (61%) diff --git a/Projects/Scripts/Accounting/Account.cs b/Projects/Scripts/Accounting/Account.cs index 8ff0ab711..635782b9b 100644 --- a/Projects/Scripts/Accounting/Account.cs +++ b/Projects/Scripts/Accounting/Account.cs @@ -427,9 +427,9 @@ namespace Server.Accounting EventSink.Login += EventSink_Login; } - private static void EventSink_Connected( ConnectedEventArgs e ) + private static void EventSink_Connected(Mobile m) { - if ( !(e.Mobile.Account is Account acc) ) + if ( !(m.Account is Account acc) ) return; if ( acc.Young && acc.m_YoungTimer == null ) @@ -439,9 +439,9 @@ namespace Server.Accounting } } - private static void EventSink_Disconnected( DisconnectedEventArgs e ) + private static void EventSink_Disconnected(Mobile m) { - if ( !(e.Mobile.Account is Account acc) ) + if ( !(m.Account is Account acc) ) return; if ( acc.m_YoungTimer != null ) @@ -450,21 +450,21 @@ namespace Server.Accounting acc.m_YoungTimer = null; } - if ( !(e.Mobile is PlayerMobile m) ) + if ( !(m is PlayerMobile pm) ) return; - acc.m_TotalGameTime += DateTime.UtcNow - m.SessionStart; + acc.m_TotalGameTime += DateTime.UtcNow - pm.SessionStart; } - private static void EventSink_Login( LoginEventArgs e ) + private static void EventSink_Login(Mobile m) { - if ( !(e.Mobile is PlayerMobile m) ) + if ( !(m is PlayerMobile pm) ) return; if ( !(m.Account is Account acc) ) return; - if ( m.Young && acc.Young ) + if ( pm.Young && acc.Young ) { TimeSpan ts = YoungDuration - acc.TotalGameTime; int hours = Math.Max( (int) ts.TotalHours, 0 ); diff --git a/Projects/Scripts/Accounting/AccountHandler.cs b/Projects/Scripts/Accounting/AccountHandler.cs index 31c131b6a..262ecad3a 100644 --- a/Projects/Scripts/Accounting/AccountHandler.cs +++ b/Projects/Scripts/Accounting/AccountHandler.cs @@ -191,11 +191,8 @@ namespace Server.Misc } } - private static void EventSink_DeleteRequest(DeleteRequestEventArgs e) + private static void EventSink_DeleteRequest(NetState state, int index) { - NetState state = e.State; - int index = e.Index; - if (!(state.Account is Account acct)) { state.Dispose(); diff --git a/Projects/Scripts/Accounting/Accounts.cs b/Projects/Scripts/Accounting/Accounts.cs index c00abd807..5b3a710a0 100644 --- a/Projects/Scripts/Accounting/Accounts.cs +++ b/Projects/Scripts/Accounting/Accounts.cs @@ -65,7 +65,7 @@ namespace Server.Accounting } } - public static void Save(WorldSaveEventArgs e) + public static void Save(bool message) { if (!Directory.Exists("Saves/Accounts")) Directory.CreateDirectory("Saves/Accounts"); diff --git a/Projects/Scripts/Commands/Dupe.cs b/Projects/Scripts/Commands/Dupe.cs index 556dd8116..3516c87fa 100644 --- a/Projects/Scripts/Commands/Dupe.cs +++ b/Projects/Scripts/Commands/Dupe.cs @@ -96,7 +96,7 @@ namespace Server.Commands { var paramList = c.GetParameters(); object[] args = paramList.Length == 0 ? null : new object[paramList.Length]; - Array.Fill(args, Type.Missing); + if (args != null) Array.Fill(args, Type.Missing); try { from.SendMessage("Duping {0}...", m_Amount); diff --git a/Projects/Scripts/Commands/VisibilityList.cs b/Projects/Scripts/Commands/VisibilityList.cs index 6e7afd9ec..6f83ffb7d 100644 --- a/Projects/Scripts/Commands/VisibilityList.cs +++ b/Projects/Scripts/Commands/VisibilityList.cs @@ -5,7 +5,7 @@ using Server.Targeting; namespace Server.Commands { - public class VisibilityList + public static class VisibilityList { public static void Initialize() { @@ -16,9 +16,9 @@ namespace Server.Commands CommandSystem.Register("VisClear", AccessLevel.Counselor, VisClear_OnCommand); } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - if (e.Mobile is PlayerMobile pm) pm.VisibilityList.Clear(); + (m as PlayerMobile)?.VisibilityList.Clear(); } [Usage("Vis")] @@ -138,4 +138,4 @@ namespace Server.Commands } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Engines/Chat/Chatold.cs b/Projects/Scripts/Engines/Chat/Chatold.cs index 0f3626116..a0e65be65 100644 --- a/Projects/Scripts/Engines/Chat/Chatold.cs +++ b/Projects/Scripts/Engines/Chat/Chatold.cs @@ -1,15 +1,15 @@ namespace Server.Chat { - public class ChatSystem + public static class ChatSystem { public static void Initialize() { EventSink.ChatRequest += EventSink_ChatRequest; } - private static void EventSink_ChatRequest(ChatRequestEventArgs e) + private static void EventSink_ChatRequest(Mobile m) { - e.Mobile.SendMessage("Chat is not currently supported."); + m.SendMessage("Chat is not currently supported."); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Engines/ConPVP/DuelContext.cs b/Projects/Scripts/Engines/ConPVP/DuelContext.cs index 0e14694cb..6cfe4eefd 100644 --- a/Projects/Scripts/Engines/ConPVP/DuelContext.cs +++ b/Projects/Scripts/Engines/ConPVP/DuelContext.cs @@ -1,6 +1,7 @@ using System; using System.Collections; using System.Collections.Generic; +using System.Linq; using Server.Engines.PartySystem; using Server.Factions; using Server.Gumps; @@ -160,7 +161,7 @@ namespace Server.Engines.ConPVP if (spell is RecallSpell) from.SendMessage("You may not cast this spell."); - string title = null; + string title; string option; switch (spell) @@ -498,7 +499,7 @@ namespace Server.Engines.ConPVP DuelPlayer pl = Find(mob); - if (pl?.Eliminated == true || m_EventGame?.OnDeath(mob, corpse) == false) + if (pl?.Eliminated != false || m_EventGame?.OnDeath(mob, corpse) == false) return; pl.Eliminated = true; @@ -1075,30 +1076,13 @@ namespace Server.Engines.ConPVP } } - public static bool CheckCombat(Mobile m) + public static bool CheckCombat(Mobile m) => + m.Aggressed.Any(info => info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay) || + m.Aggressors.Any(info => info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay); + + private static void EventSink_Login(Mobile m) { - for (int i = 0; i < m.Aggressed.Count; ++i) - { - AggressorInfo info = m.Aggressed[i]; - - if (info.Defender.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay) - return true; - } - - for (int i = 0; i < m.Aggressors.Count; ++i) - { - AggressorInfo info = m.Aggressors[i]; - - if (info.Attacker.Player && DateTime.UtcNow - info.LastCombatTime < CombatDelay) - return true; - } - - return false; - } - - private static void EventSink_Login(LoginEventArgs e) - { - if (!(e.Mobile is PlayerMobile pm)) + if (!(m is PlayerMobile pm)) return; DuelContext dc = pm.DuelContext; diff --git a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs index 193961bae..8a2b2d862 100644 --- a/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs +++ b/Projects/Scripts/Engines/Doom/LeverPuzzle/LeverPuzzleRegions.cs @@ -19,9 +19,8 @@ namespace Server.Engines.Doom EventSink.Login += OnLogin; } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - Mobile m = e.Mobile; Rectangle2D rect = LeverPuzzleController.lr_Rect; if (m.X >= rect.X && m.X <= rect.X + 10 && m.Y >= rect.Y && m.Y <= rect.Y + 10 && m.Map == Map.Internal) { diff --git a/Projects/Scripts/Engines/Factions/Core/Faction.cs b/Projects/Scripts/Engines/Factions/Core/Faction.cs index 373a7cb30..c3d0443a5 100644 --- a/Projects/Scripts/Engines/Factions/Core/Faction.cs +++ b/Projects/Scripts/Engines/Factions/Core/Faction.cs @@ -940,7 +940,7 @@ namespace Server.Factions int silver = killerState.Faction.AwardSilver(killer, bc.FactionSilverWorth); if (silver > 0) - killer.SendLocalizedMessage(1042748, + killer?.SendLocalizedMessage(1042748, silver.ToString("N0")); // Thou hast earned ~1_AMOUNT~ silver for vanquishing the vile creature. } @@ -981,7 +981,7 @@ namespace Server.Factions { if (victimState.KillPoints <= -6) { - killer.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. + killer?.SendLocalizedMessage(501693); // This victim is not worth enough to get kill points from. #region Ethics @@ -1029,7 +1029,7 @@ namespace Server.Factions int silver = killerState.Faction.AwardSilver(killer, award * 40); if (silver > 0) - killer.SendLocalizedMessage(1042736, + killer?.SendLocalizedMessage(1042736, $"{silver:N0} silver\t{victim.Name}"); // You have earned ~1_SILVER_AMOUNT~ pieces for vanquishing ~2_PLAYER_NAME~! } @@ -1038,9 +1038,9 @@ namespace Server.Factions int offset = award != 1 ? 0 : 2; // for pluralization - string args = $"{award}\t{victim.Name}\t{killer.Name}"; + string args = $"{award}\t{victim.Name}\t{killer?.Name}"; - killer.SendLocalizedMessage(1042737 + offset, + killer?.SendLocalizedMessage(1042737 + offset, args); // Thou hast been honored with ~1_KILL_POINTS~ kill point(s) for vanquishing ~2_DEAD_PLAYER~! victim.SendLocalizedMessage(1042738 + offset, args); // Thou has lost ~1_KILL_POINTS~ kill point(s) to ~3_ATTACKER_NAME~ for being vanquished! @@ -1072,24 +1072,19 @@ namespace Server.Factions } else { - killer.SendLocalizedMessage( + killer?.SendLocalizedMessage( 1042231); // You have recently defeated this enemy and thus their death brings you no honor. } } } } - private static void EventSink_Logout(LogoutEventArgs e) + private static void EventSink_Logout(Mobile m) { - e.Mobile.Backpack?.FindItemsByType().ForEach(sigil => sigil.ReturnHome()); + m.Backpack?.FindItemsByType().ForEach(sigil => sigil.ReturnHome()); } - private static void EventSink_Login(LoginEventArgs e) - { - Mobile mob = e.Mobile; - - CheckLeaveTimer(mob); - } + private static void EventSink_Login(Mobile m) => CheckLeaveTimer(m); public static void WriteReference(IGenericWriter writer, Faction fact) { @@ -1102,10 +1097,7 @@ namespace Server.Factions { int idx = reader.ReadEncodedInt() - 1; - if (idx >= 0 && idx < Factions.Count) - return Factions[idx]; - - return null; + return idx >= 0 && idx < Factions.Count ? Factions[idx] : null; } public static Faction Find(Mobile mob, bool inherit = false, bool creatureAllegiances = false) diff --git a/Projects/Scripts/Engines/Factions/Core/Keywords.cs b/Projects/Scripts/Engines/Factions/Core/Keywords.cs index ec2955400..86211d1b3 100644 --- a/Projects/Scripts/Engines/Factions/Core/Keywords.cs +++ b/Projects/Scripts/Engines/Factions/Core/Keywords.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server.Factions { - public class Keywords + public static class Keywords { public static void Initialize() { diff --git a/Projects/Scripts/Engines/Help/HelpGump.cs b/Projects/Scripts/Engines/Help/HelpGump.cs index f99b5c308..151c9b99c 100644 --- a/Projects/Scripts/Engines/Help/HelpGump.cs +++ b/Projects/Scripts/Engines/Help/HelpGump.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Server.Engines.ConPVP; using Server.Factions; using Server.Gumps; @@ -194,19 +195,17 @@ namespace Server.Engines.Help EventSink.HelpRequest += EventSink_HelpRequest; } - private static void EventSink_HelpRequest(HelpRequestEventArgs e) + private static void EventSink_HelpRequest(Mobile m) { - foreach (Gump g in e.Mobile.NetState.Gumps) - if (g is HelpGump) - return; + if (m.NetState.Gumps.OfType().Any()) return; - if (!PageQueue.CheckAllowedToPage(e.Mobile)) + if (!PageQueue.CheckAllowedToPage(m)) return; - if (PageQueue.Contains(e.Mobile)) - e.Mobile.SendMenu(new ContainedMenu(e.Mobile)); + if (PageQueue.Contains(m)) + m.SendMenu(new ContainedMenu(m)); else - e.Mobile.SendGump(new HelpGump(e.Mobile)); + m.SendGump(new HelpGump(m)); } private static bool IsYoung(Mobile m) => m is PlayerMobile mobile && mobile.Young; diff --git a/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs b/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs index f5adb31cd..9973f4571 100644 --- a/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs +++ b/Projects/Scripts/Engines/MLQuests/MLQuestSystem.cs @@ -535,9 +535,9 @@ namespace Server.Engines.MLQuests } } - public static void EventSink_QuestGumpRequest(QuestGumpRequestArgs args) + public static void EventSink_QuestGumpRequest(Mobile m) { - if (!Enabled || !(args.Mobile is PlayerMobile pm)) + if (!Enabled || !(m is PlayerMobile pm)) return; pm.SendGump(new QuestLogGump(pm)); diff --git a/Projects/Scripts/Engines/Party/Party.cs b/Projects/Scripts/Engines/Party/Party.cs index 015ccbea4..682559df0 100644 --- a/Projects/Scripts/Engines/Party/Party.cs +++ b/Projects/Scripts/Engines/Party/Party.cs @@ -134,9 +134,8 @@ namespace Server.Engines.PartySystem } } - public static void EventSink_PlayerDeath(PlayerDeathEventArgs e) + public static void EventSink_PlayerDeath(Mobile from) { - Mobile from = e.Mobile; Party p = Get(from); if (p != null) @@ -152,9 +151,8 @@ namespace Server.Engines.PartySystem } } - public static void EventSink_Login(LoginEventArgs e) + public static void EventSink_Login(Mobile from) { - Mobile from = e.Mobile; Party p = Get(from); if (p != null) @@ -163,9 +161,8 @@ namespace Server.Engines.PartySystem from.Party = null; } - public static void EventSink_Logout(LogoutEventArgs e) + public static void EventSink_Logout(Mobile from) { - Mobile from = e.Mobile; Party p = Get(from); p?.Remove(from); diff --git a/Projects/Scripts/Engines/Plants/PlantSystem.cs b/Projects/Scripts/Engines/Plants/PlantSystem.cs index 454737d49..95b1fc057 100644 --- a/Projects/Scripts/Engines/Plants/PlantSystem.cs +++ b/Projects/Scripts/Engines/Plants/PlantSystem.cs @@ -407,10 +407,8 @@ namespace Server.Engines.Plants EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs args) + private static void EventSink_Login(Mobile from) { - Mobile from = args.Mobile; - from.Backpack?.FindItemsByType().ForEach(plant => { if (plant.IsGrowable) @@ -443,7 +441,7 @@ namespace Server.Engines.Plants GrowAll(); } - private static void EventSink_WorldSave(WorldSaveEventArgs args) + private static void EventSink_WorldSave(bool message) { GrowAll(); } diff --git a/Projects/Scripts/Engines/VeteranRewards/RewardSystem.cs b/Projects/Scripts/Engines/VeteranRewards/RewardSystem.cs index 504b72e71..c140c2edb 100644 --- a/Projects/Scripts/Engines/VeteranRewards/RewardSystem.cs +++ b/Projects/Scripts/Engines/VeteranRewards/RewardSystem.cs @@ -252,7 +252,7 @@ namespace Server.Engines.VeteranRewards if (args == null && entries[j].Args.Length == 0) return i + 1; - if (args.Length == entries[j].Args.Length) + if (args?.Length == entries[j].Args.Length) { bool match = true; @@ -467,15 +467,15 @@ namespace Server.Engines.VeteranRewards EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs e) + private static void EventSink_Login(Mobile m) { - if (!e.Mobile.Alive) + if (!m.Alive) return; - ComputeRewardInfo(e.Mobile, out int cur, out int max, out int level); + ComputeRewardInfo(m, out int cur, out int max, out int level); - if (e.Mobile.SkillsCap == 7000 || e.Mobile.SkillsCap == 7050 || e.Mobile.SkillsCap == 7100 || - e.Mobile.SkillsCap == 7150 || e.Mobile.SkillsCap == 7200) + if (m.SkillsCap == 7000 || m.SkillsCap == 7050 || m.SkillsCap == 7100 || + m.SkillsCap == 7150 || m.SkillsCap == 7200) { if (level > 4) level = 4; @@ -483,19 +483,19 @@ namespace Server.Engines.VeteranRewards level = 0; if (SkillCapRewards) - e.Mobile.SkillsCap = 7000 + level * 50; + m.SkillsCap = 7000 + level * 50; else - e.Mobile.SkillsCap = 7000; + m.SkillsCap = 7000; } - if (Core.ML && e.Mobile is PlayerMobile mobile && !mobile.HasStatReward && HasHalfLevel(mobile)) + if (Core.ML && m is PlayerMobile pm && !pm.HasStatReward && HasHalfLevel(pm)) { - mobile.HasStatReward = true; - mobile.StatCap += 5; + pm.HasStatReward = true; + pm.StatCap += 5; } if (cur < max) - e.Mobile.SendGump(new RewardNoticeGump(e.Mobile)); + m.SendGump(new RewardNoticeGump(m)); } } diff --git a/Projects/Scripts/Engines/Virtues/VirtueGump.cs b/Projects/Scripts/Engines/Virtues/VirtueGump.cs index 9f9780989..9f226496b 100644 --- a/Projects/Scripts/Engines/Virtues/VirtueGump.cs +++ b/Projects/Scripts/Engines/Virtues/VirtueGump.cs @@ -64,47 +64,41 @@ namespace Server m_Callbacks[gumpID] = callback; } - private static void EventSink_VirtueItemRequest(VirtueItemRequestEventArgs e) + private static void EventSink_VirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) { - if (e.Beholder != e.Beheld) + if (beholder != beheld) return; - e.Beholder.CloseGump(); + beholder.CloseGump(); - if (e.Beholder.Kills >= 5) + if (beholder.Kills >= 5) { - e.Beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue. + beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue. return; } - if (m_Callbacks.TryGetValue(e.GumpID, out OnVirtueUsed callback)) - callback(e.Beholder); + if (m_Callbacks.TryGetValue(gumpID, out OnVirtueUsed callback)) + callback(beholder); else - e.Beholder.SendLocalizedMessage(1052066); // That virtue is not active yet. + beholder.SendLocalizedMessage(1052066); // That virtue is not active yet. } - private static void EventSink_VirtueMacroRequest(VirtueMacroRequestEventArgs e) + private static void EventSink_VirtueMacroRequest(Mobile beholder, int virtue) { - var virtueID = e.VirtueID switch + var virtueID = virtue switch { - 0 => // Honor - 107, - 1 => // Sacrifice - 110, - 2 => // Valor; - 112, + 0 => 107, // Honor + 1 => 110, // Sacrifice + 2 => 112, // Valor; _ => 0 }; - EventSink_VirtueItemRequest(new VirtueItemRequestEventArgs(e.Mobile, e.Mobile, virtueID)); + EventSink_VirtueItemRequest(beholder, beholder, virtueID); } - private static void EventSink_VirtueGumpRequest(VirtueGumpRequestEventArgs e) + private static void EventSink_VirtueGumpRequest(Mobile beholder, Mobile beheld) { - Mobile beholder = e.Beholder; - Mobile beheld = e.Beheld; - if (beholder == beheld && beholder.Kills >= 5) { beholder.SendLocalizedMessage(1049609); // Murderers cannot invoke this virtue. diff --git a/Projects/Scripts/Gumps/ReportMurderer.cs b/Projects/Scripts/Gumps/ReportMurderer.cs index 5ae15f756..6eec239b0 100644 --- a/Projects/Scripts/Gumps/ReportMurderer.cs +++ b/Projects/Scripts/Gumps/ReportMurderer.cs @@ -17,10 +17,8 @@ namespace Server.Gumps EventSink.PlayerDeath += EventSink_PlayerDeath; } - public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + public static void EventSink_PlayerDeath(Mobile m) { - Mobile m = e.Mobile; - List killers = new List(); List toGive = new List(); @@ -46,7 +44,7 @@ namespace Server.Gumps { int n = Notoriety.Compute( g, m ); - int theirKarma = m.Karma, ourKarma = g.Karma; + int ourKarma = g.Karma; bool innocent = n == Notoriety.Innocent; bool criminal = n == Notoriety.Criminal || n == Notoriety.Murderer; diff --git a/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs b/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs index 866d003ec..b1216ff0f 100644 --- a/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs +++ b/Projects/Scripts/Holiday Stuff/Halloween/2006/Engines/TrickOrTreat.cs @@ -7,7 +7,7 @@ using Server.Targeting; namespace Server.Engines.Events { - public class TrickOrTreat + public static class TrickOrTreat { public static TimeSpan OneSecond = TimeSpan.FromSeconds(1); diff --git a/Projects/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs b/Projects/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs index 6e324b69c..8797effab 100644 --- a/Projects/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs +++ b/Projects/Scripts/Holiday Stuff/Halloween/2012/Engines/PlayerZombies.cs @@ -64,10 +64,10 @@ namespace Server.Engines.Events } } - public static void EventSink_PlayerDeath( PlayerDeathEventArgs e ) + public static void EventSink_PlayerDeath(Mobile m) { - if ( e.Mobile is PlayerMobile player && !player.Deleted && m_Timer.Running && !m_DeathQueue.Contains( player ) && m_DeathQueue.Count < m_DeathQueueLimit ) - m_DeathQueue.Add( player ); + if (m is PlayerMobile pm && !pm.Deleted && m_Timer.Running && !m_DeathQueue.Contains(pm) && m_DeathQueue.Count < m_DeathQueueLimit) + m_DeathQueue.Add(pm); } private static void Clear_Callback() diff --git a/Projects/Scripts/Items/Construction/Doors/BaseDoor.cs b/Projects/Scripts/Items/Construction/Doors/BaseDoor.cs index d6125d3e3..9d224bb53 100644 --- a/Projects/Scripts/Items/Construction/Doors/BaseDoor.cs +++ b/Projects/Scripts/Items/Construction/Doors/BaseDoor.cs @@ -215,61 +215,58 @@ namespace Server.Items } } - private static void EventSink_OpenDoorMacroUsed(OpenDoorMacroEventArgs args) + private static void EventSink_OpenDoorMacroUsed(Mobile m) { - Mobile m = args.Mobile; + if (m.Map == null) return; - if (m.Map != null) + int x = m.X, y = m.Y; + + switch (m.Direction & Direction.Mask) { - int x = m.X, y = m.Y; - - switch (m.Direction & Direction.Mask) - { - case Direction.North: - --y; - break; - case Direction.Right: - ++x; - --y; - break; - case Direction.East: - ++x; - break; - case Direction.Down: - ++x; - ++y; - break; - case Direction.South: - ++y; - break; - case Direction.Left: - --x; - ++y; - break; - case Direction.West: - --x; - break; - case Direction.Up: - --x; - --y; - break; - } - - Sector sector = m.Map.GetSector(x, y); - - foreach (Item item in sector.Items) - if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z && - m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item)) - { - if (m.CheckAlive()) - { - m.SendLocalizedMessage(500024); // Opening door... - item.OnDoubleClick(m); - } - - break; - } + case Direction.North: + --y; + break; + case Direction.Right: + ++x; + --y; + break; + case Direction.East: + ++x; + break; + case Direction.Down: + ++x; + ++y; + break; + case Direction.South: + ++y; + break; + case Direction.Left: + --x; + ++y; + break; + case Direction.West: + --x; + break; + case Direction.Up: + --x; + --y; + break; } + + Sector sector = m.Map.GetSector(x, y); + + foreach (Item item in sector.Items) + if (item.Location.X == x && item.Location.Y == y && item.Z + item.ItemData.Height > m.Z && + m.Z + 16 > item.Z && item is BaseDoor && m.CanSee(item) && m.InLOS(item)) + { + if (m.CheckAlive()) + { + m.SendLocalizedMessage(500024); // Opening door... + item.OnDoubleClick(m); + } + + break; + } } public static Point3D GetOffset(DoorFacing facing) => m_Offsets[(int)facing]; diff --git a/Projects/Scripts/Items/Food/Beverage.cs b/Projects/Scripts/Items/Food/Beverage.cs index 421a19256..8e154f955 100644 --- a/Projects/Scripts/Items/Food/Beverage.cs +++ b/Projects/Scripts/Items/Food/Beverage.cs @@ -1048,9 +1048,9 @@ namespace Server.Items EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs e) + private static void EventSink_Login(Mobile m) { - CheckHeaveTimer(e.Mobile); + CheckHeaveTimer(m); } public static void CheckHeaveTimer(Mobile from) diff --git a/Projects/Scripts/Items/Misc/Corpses/Corpse.cs b/Projects/Scripts/Items/Misc/Corpses/Corpse.cs index 642e9010b..03367cc66 100644 --- a/Projects/Scripts/Items/Misc/Corpses/Corpse.cs +++ b/Projects/Scripts/Items/Misc/Corpses/Corpse.cs @@ -193,16 +193,7 @@ namespace Server.Items } [CommandProperty(AccessLevel.GameMaster)] - public virtual bool InstancedCorpse - { - get - { - if (!Core.SE) - return false; - - return DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime; - } - } + public virtual bool InstancedCorpse => Core.SE && DateTime.UtcNow < TimeOfDeath + InstancedCorpseTime; public override bool IsDecoContainer => false; diff --git a/Projects/Scripts/Items/Misc/Teleporter.cs b/Projects/Scripts/Items/Misc/Teleporter.cs index 0c7df0994..6ea179586 100644 --- a/Projects/Scripts/Items/Misc/Teleporter.cs +++ b/Projects/Scripts/Items/Misc/Teleporter.cs @@ -630,10 +630,8 @@ namespace Server.Items EventSink.Logout += EventSink_Logout; } - public static void EventSink_Logout(LogoutEventArgs e) + public static void EventSink_Logout(Mobile from) { - Mobile from = e.Mobile; - if (from == null || !m_Table.TryGetValue(from, out TeleportingInfo info)) return; diff --git a/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs b/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs index 8a7c8f581..94e8a6bfe 100644 --- a/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs +++ b/Projects/Scripts/Items/Skill Items/Magical/Spellbook.cs @@ -245,6 +245,7 @@ namespace Server.Items { EventSink.OpenSpellbookRequest += EventSink_OpenSpellbookRequest; EventSink.CastSpellRequest += EventSink_CastSpellRequest; + EventSink.TargetedSpell += EventSink_TargetedSpell; CommandSystem.Register("AllSpells", AccessLevel.GameMaster, AllSpells_OnCommand); } @@ -278,14 +279,12 @@ namespace Server.Items } } - private static void EventSink_OpenSpellbookRequest(OpenSpellbookRequestEventArgs e) + private static void EventSink_OpenSpellbookRequest(Mobile from, int typeID) { - Mobile from = e.Mobile; - if (!DesignContext.Check(from)) return; // They are customizing - var type = e.Type switch + var type = typeID switch { 1 => SpellbookType.Regular, 2 => SpellbookType.Necromancer, @@ -302,15 +301,32 @@ namespace Server.Items book?.DisplayTo(from); } - private static void EventSink_CastSpellRequest(CastSpellRequestEventArgs e) + private static void EventSink_TargetedSpell(Mobile from, IEntity target, int spellId) { - Mobile from = e.Mobile; + if (!DesignContext.Check(from)) return; // They are customizing + Spellbook book = Find(from, spellId); + + if (book?.HasSpell(spellId) != true) + { + from.SendLocalizedMessage(500015); // You do not have that spell! + return; + } + + SpecialMove move = SpellRegistry.GetSpecialMove(spellId); + + if (move != null) + SpecialMove.SetCurrentMove(from, move); + else + SpellRegistry.NewSpell(spellId, @from, null)?.Cast(); + } + + private static void EventSink_CastSpellRequest(Mobile from, int spellID, Item item) + { if (!DesignContext.Check(from)) return; // They are customizing - Spellbook book = e.Spellbook as Spellbook; - int spellID = e.SpellID; + Spellbook book = item as Spellbook; if (book?.HasSpell(spellID) != true) book = Find(from, spellID); @@ -688,7 +704,7 @@ namespace Server.Items if ((prop = Attributes.RegenMana) != 0) list.Add(1060440, prop.ToString()); // mana regeneration ~1_val~ - if ((prop = Attributes.NightSight) != 0) + if ((Attributes.NightSight) != 0) list.Add(1060441); // night sight if ((prop = Attributes.ReflectPhysical) != 0) @@ -700,7 +716,7 @@ namespace Server.Items if ((prop = Attributes.RegenHits) != 0) list.Add(1060444, prop.ToString()); // hit point regeneration ~1_val~ - if ((prop = Attributes.SpellChanneling) != 0) + if ((Attributes.SpellChanneling) != 0) list.Add(1060482); // spell channeling if ((prop = Attributes.SpellDamage) != 0) diff --git a/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs b/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs index 7ff01a088..8b154506c 100644 --- a/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs +++ b/Projects/Scripts/Items/Skill Items/Misc/Bandage.cs @@ -70,30 +70,27 @@ namespace Server.Items } } - private static void EventSink_BandageTargetRequest(BandageTargetRequestEventArgs e) + private static void EventSink_BandageTargetRequest(Mobile from, Item item, Mobile target) { - if (!(e.Bandage is Bandage b) || b.Deleted) + if (!(item is Bandage b) || b.Deleted) return; - Mobile from = e.Mobile; - - if (from.InRange(b.GetWorldLocation(), Range)) - { - if (from.Target != null) - { - Target.Cancel(from); - from.Target = null; - } - - from.RevealingAction(); - from.SendLocalizedMessage(500948); // Who will you use the bandages on? - - new InternalTarget(b).Invoke(from, e.Target); - } - else + if (!from.InRange(b.GetWorldLocation(), Range)) { from.SendLocalizedMessage(500295); // You are too far away to do that. + return; } + + if (from.Target != null) + { + Target.Cancel(from); + from.Target = null; + } + + from.RevealingAction(); + from.SendLocalizedMessage(500948); // Who will you use the bandages on? + + new InternalTarget(b).Invoke(from, target); } private class InternalTarget : Target @@ -203,7 +200,7 @@ namespace Server.Items { StopHeal(); - int healerNumber = -1, patientNumber = -1; + int healerNumber, patientNumber; bool playSound = true; bool checkSkills = false; diff --git a/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs b/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs index dff3bf72e..09d7a973f 100644 --- a/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs +++ b/Projects/Scripts/Items/Weapons/Abilities/WeaponAbility.cs @@ -389,14 +389,12 @@ namespace Server.Items EventSink.SetAbility += EventSink_SetAbility; } - private static void EventSink_SetAbility(SetAbilityEventArgs e) + private static void EventSink_SetAbility(Mobile m, int index) { - int index = e.Index; - if (index == 0) - ClearCurrentAbility(e.Mobile); + ClearCurrentAbility(m); else if (index >= 1 && index < Abilities.Length) - SetCurrentAbility(e.Mobile, Abilities[index]); + SetCurrentAbility(m, Abilities[index]); } private static void AddContext(Mobile m, WeaponAbilityContext context) diff --git a/Projects/Scripts/Items/Weapons/Fists.cs b/Projects/Scripts/Items/Weapons/Fists.cs index e9c57f992..c04bb0a74 100644 --- a/Projects/Scripts/Items/Weapons/Fists.cs +++ b/Projects/Scripts/Items/Weapons/Fists.cs @@ -216,13 +216,11 @@ namespace Server.Items return (item == null || item is Spellbook) && m.FindItemOnLayer(Layer.TwoHanded) == null; } - private static void EventSink_DisarmRequest(DisarmRequestEventArgs e) + private static void EventSink_DisarmRequest(Mobile m) { if (Core.AOS) return; - Mobile m = e.Mobile; - #region Dueling if (!DuelContext.AllowSpecialAbility(m, "Disarm", true)) @@ -251,13 +249,11 @@ namespace Server.Items } } - private static void EventSink_StunRequest(StunRequestEventArgs e) + private static void EventSink_StunRequest(Mobile m) { if (Core.AOS) return; - Mobile m = e.Mobile; - #region Dueling if (!DuelContext.AllowSpecialAbility(m, "Stun", true)) diff --git a/Projects/Scripts/Misc/Animations.cs b/Projects/Scripts/Misc/Animations.cs index d4515e671..0219722f7 100644 --- a/Projects/Scripts/Misc/Animations.cs +++ b/Projects/Scripts/Misc/Animations.cs @@ -1,31 +1,23 @@ namespace Server.Misc { - public class Animations + public static class Animations { public static void Initialize() { EventSink.AnimateRequest += EventSink_AnimateRequest; } - private static void EventSink_AnimateRequest(AnimateRequestEventArgs e) + private static void EventSink_AnimateRequest(Mobile from, string actionName) { - Mobile from = e.Mobile; - - int action; - - switch (e.Action) + int action = actionName switch { - case "bow": - action = 32; - break; - case "salute": - action = 33; - break; - default: return; - } + "bow" => 32, + "salute" => 33, + _ => 0, + }; - if (from.Alive && !from.Mounted && from.Body.IsHuman) + if (action > 0 && from.Alive && !from.Mounted && from.Body.IsHuman) from.Animate(action, 5, 1, true, false, 0); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/AttackMessage.cs b/Projects/Scripts/Misc/AttackMessage.cs index 0687281f7..fffec074d 100644 --- a/Projects/Scripts/Misc/AttackMessage.cs +++ b/Projects/Scripts/Misc/AttackMessage.cs @@ -59,4 +59,4 @@ namespace Server.Misc return false; } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/Broadcasts.cs b/Projects/Scripts/Misc/Broadcasts.cs index 65d5f79a3..55a80fa98 100644 --- a/Projects/Scripts/Misc/Broadcasts.cs +++ b/Projects/Scripts/Misc/Broadcasts.cs @@ -1,14 +1,14 @@ namespace Server.Misc { - public class Broadcasts + public static class Broadcasts { public static void Initialize() { - EventSink.Crashed += EventSink_Crashed; + EventSink.ServerCrashed += EventSink_Crashed; EventSink.Shutdown += EventSink_Shutdown; } - public static void EventSink_Crashed(CrashedEventArgs e) + public static void EventSink_Crashed(ServerCrashedEventArgs e) { try { @@ -20,16 +20,16 @@ namespace Server.Misc } } - public static void EventSink_Shutdown(ShutdownEventArgs e) + public static void EventSink_Shutdown() { -/* try - { - World.Broadcast(0x35, true, "The server has shut down."); - } - catch - { - // ignored - }*/ + /* try + { + World.Broadcast(0x35, true, "The server has shut down."); + } + catch + { + // ignored + }*/ } } } diff --git a/Projects/Scripts/Misc/BuffIcons.cs b/Projects/Scripts/Misc/BuffIcons.cs index 6884f63c9..6a06ae139 100644 --- a/Projects/Scripts/Misc/BuffIcons.cs +++ b/Projects/Scripts/Misc/BuffIcons.cs @@ -11,11 +11,13 @@ namespace Server public static void Initialize() { if (Enabled) - EventSink.ClientVersionReceived += delegate(ClientVersionReceivedArgs args) - { - if (args.State.Mobile is PlayerMobile pm) - Timer.DelayCall(TimeSpan.Zero, pm.ResendBuffs); - }; + EventSink.ClientVersionReceived += ResendBuffsOnClientVersionReceived; + } + + public static void ResendBuffsOnClientVersionReceived(NetState ns, ClientVersion cv) + { + if (ns.Mobile is PlayerMobile pm) + Timer.DelayCall(TimeSpan.Zero, pm.ResendBuffs); } #region Properties @@ -284,4 +286,4 @@ namespace Server m_Stream.Fill(4); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/CharacterCreation.cs b/Projects/Scripts/Misc/CharacterCreation.cs index 64fcdd999..9c5b32566 100644 --- a/Projects/Scripts/Misc/CharacterCreation.cs +++ b/Projects/Scripts/Misc/CharacterCreation.cs @@ -1164,7 +1164,7 @@ namespace Server.Misc if (m_Mobile?.EquipItem(item) == true) return; - Container pack = m_Mobile.Backpack; + Container pack = m_Mobile?.Backpack; if (!mustEquip && pack != null) pack.DropItem(item); diff --git a/Projects/Scripts/Misc/ClientVerification.cs b/Projects/Scripts/Misc/ClientVerification.cs index eacc7aa6d..22a64f755 100644 --- a/Projects/Scripts/Misc/ClientVerification.cs +++ b/Projects/Scripts/Misc/ClientVerification.cs @@ -56,13 +56,11 @@ namespace Server.Misc } } - private static void EventSink_ClientVersionReceived(ClientVersionReceivedArgs e) + private static void EventSink_ClientVersionReceived(NetState state, ClientVersion version) { string kickMessage = null; - NetState state = e.State; - ClientVersion version = e.Version; - if (state.Mobile == null || state.Mobile.AccessLevel > AccessLevel.Player) + if (state.Mobile?.AccessLevel != AccessLevel.Player) return; if (Required != null && version < Required && (m_OldClientResponse == OldClientResponse.Kick || diff --git a/Projects/Scripts/Misc/CrashGuard.cs b/Projects/Scripts/Misc/CrashGuard.cs index 26d9e31bb..9ff027311 100644 --- a/Projects/Scripts/Misc/CrashGuard.cs +++ b/Projects/Scripts/Misc/CrashGuard.cs @@ -7,20 +7,20 @@ using Server.Network; namespace Server.Misc { - public class CrashGuard + public static class CrashGuard { - private static bool Enabled = true; - private static bool SaveBackup = true; - private static bool RestartServer = true; - private static bool GenerateReport = true; + private static readonly bool Enabled = true; + private static readonly bool SaveBackup = true; + private static readonly bool RestartServer = true; + private static readonly bool GenerateReport = true; public static void Initialize() { if (Enabled) // If enabled, register our crash event handler - EventSink.Crashed += CrashGuard_OnCrash; + EventSink.ServerCrashed += CrashGuard_OnCrash; } - public static void CrashGuard_OnCrash(CrashedEventArgs e) + public static void CrashGuard_OnCrash(ServerCrashedEventArgs e) { if (GenerateReport) GenerateCrashReport(e); @@ -61,7 +61,7 @@ namespace Server.Misc private static string Combine(string path1, string path2) => path1.Length == 0 ? path2 : Path.Combine(path1, path2); - private static void Restart(CrashedEventArgs e) + private static void Restart(ServerCrashedEventArgs e) { string root = GetRoot(); @@ -152,7 +152,7 @@ namespace Server.Misc } } - private static void GenerateCrashReport(CrashedEventArgs e) + private static void GenerateCrashReport(ServerCrashedEventArgs e) { Console.Write("Crash: Generating report..."); diff --git a/Projects/Scripts/Misc/Fastwalk.cs b/Projects/Scripts/Misc/Fastwalk.cs index 232986b7a..a9861974c 100644 --- a/Projects/Scripts/Misc/Fastwalk.cs +++ b/Projects/Scripts/Misc/Fastwalk.cs @@ -4,7 +4,7 @@ namespace Server.Misc { // This fastwalk detection is no longer required // As of B36 PlayerMobile implements movement packet throttling which more reliably controls movement speeds - public class Fastwalk + public static class Fastwalk { private static int MaxSteps = 4; // Maximum number of queued steps until fastwalk is detected private static bool Enabled = false; // Is fastwalk detection enabled? @@ -30,4 +30,4 @@ namespace Server.Misc Console.WriteLine("Client: {0}: Fast movement detected (name={1})", e.NetState, e.NetState.Mobile.Name); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/Guild.cs b/Projects/Scripts/Misc/Guild.cs index 3122401e7..c01b0aefd 100644 --- a/Projects/Scripts/Misc/Guild.cs +++ b/Projects/Scripts/Misc/Guild.cs @@ -484,9 +484,7 @@ namespace Server.Guilds public class WarTimer : Timer { - private static TimeSpan InternalDelay = TimeSpan.FromMinutes(1.0); - - public WarTimer() : base(InternalDelay, InternalDelay) => Priority = TimerPriority.FiveSeconds; + public WarTimer() : base(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.0)) => Priority = TimerPriority.FiveSeconds; public static void Initialize() { @@ -718,7 +716,7 @@ namespace Server.Guilds if (o is Guildstone stone) { - if (stone?.Guild.Disbanded != false) + if (stone.Guild.Disbanded) { from.SendMessage("The guild associated with that Guildstone no longer exists"); return; @@ -748,9 +746,9 @@ namespace Server.Guilds #region EventSinks - public static void EventSink_GuildGumpRequest(GuildGumpRequestArgs args) + public static void EventSink_GuildGumpRequest(Mobile m) { - if (!NewGuildSystem || !(args.Mobile is PlayerMobile pm)) + if (!NewGuildSystem || !(m is PlayerMobile pm)) return; if (pm.Guild == null) diff --git a/Projects/Scripts/Misc/Keywords.cs b/Projects/Scripts/Misc/Keywords.cs index 6c4ac05e6..71e04ffc4 100644 --- a/Projects/Scripts/Misc/Keywords.cs +++ b/Projects/Scripts/Misc/Keywords.cs @@ -4,7 +4,7 @@ using Server.Mobiles; namespace Server.Misc { - public class Keywords + public static class Keywords { public static void Initialize() { @@ -51,4 +51,4 @@ namespace Server.Misc } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/LightCycle.cs b/Projects/Scripts/Misc/LightCycle.cs index 0df950d41..16b39ca18 100644 --- a/Projects/Scripts/Misc/LightCycle.cs +++ b/Projects/Scripts/Misc/LightCycle.cs @@ -54,10 +54,8 @@ namespace Server } } - public static void OnLogin(LoginEventArgs args) + public static void OnLogin(Mobile m) { - Mobile m = args.Mobile; - m.CheckLightLevels(true); } diff --git a/Projects/Scripts/Misc/LoginStats.cs b/Projects/Scripts/Misc/LoginStats.cs index 8b6ca8614..0d12b425a 100644 --- a/Projects/Scripts/Misc/LoginStats.cs +++ b/Projects/Scripts/Misc/LoginStats.cs @@ -10,17 +10,15 @@ namespace Server.Misc EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs args) + private static void EventSink_Login(Mobile m) { int userCount = TcpServer.Instances.Count; int itemCount = World.Items.Count; int mobileCount = World.Mobiles.Count; - Mobile m = args.Mobile; - m.SendMessage( "Welcome, {0}! There {1} currently {2} user{3} online, with {4} item{5} and {6} mobile{7} in the world.", - args.Mobile.Name, + m.Name, userCount == 1 ? "is" : "are", userCount, userCount == 1 ? "" : "s", itemCount, itemCount == 1 ? "" : "s", diff --git a/Projects/Scripts/Misc/Paperdoll.cs b/Projects/Scripts/Misc/Paperdoll.cs index 4ba425c74..ac914ebe9 100644 --- a/Projects/Scripts/Misc/Paperdoll.cs +++ b/Projects/Scripts/Misc/Paperdoll.cs @@ -3,18 +3,15 @@ using Server.Network; namespace Server.Misc { - public class Paperdoll + public static class Paperdoll { public static void Initialize() { EventSink.PaperdollRequest += EventSink_PaperdollRequest; } - public static void EventSink_PaperdollRequest(PaperdollRequestEventArgs e) + public static void EventSink_PaperdollRequest(Mobile beholder, Mobile beheld) { - Mobile beholder = e.Beholder; - Mobile beheld = e.Beheld; - beholder.Send(new DisplayPaperdoll(beheld, Titles.ComputeTitle(beholder, beheld), beheld.AllowEquipFrom(beholder))); @@ -30,4 +27,4 @@ namespace Server.Misc } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/ProfanityProtection.cs b/Projects/Scripts/Misc/ProfanityProtection.cs index 514589214..1e777872c 100644 --- a/Projects/Scripts/Misc/ProfanityProtection.cs +++ b/Projects/Scripts/Misc/ProfanityProtection.cs @@ -10,7 +10,7 @@ namespace Server.Misc Other // some other implementation } - public class ProfanityProtection + public static class ProfanityProtection { private static bool Enabled = false; @@ -118,4 +118,4 @@ namespace Server.Misc e.Blocked = !OnProfanityDetected(from, e.Speech); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/Profile.cs b/Projects/Scripts/Misc/Profile.cs index 98731f549..a8d2c612a 100644 --- a/Projects/Scripts/Misc/Profile.cs +++ b/Projects/Scripts/Misc/Profile.cs @@ -4,7 +4,7 @@ using Server.Network; namespace Server.Misc { - public class Profile + public static class Profile { public static void Initialize() { @@ -12,21 +12,16 @@ namespace Server.Misc EventSink.ChangeProfileRequest += EventSink_ChangeProfileRequest; } - public static void EventSink_ChangeProfileRequest(ChangeProfileRequestEventArgs e) + public static void EventSink_ChangeProfileRequest(Mobile beholder, Mobile beheld, string text) { - Mobile from = e.Beholder; - - if (from.ProfileLocked) - from.SendMessage("Your profile is locked. You may not change it."); + if (beholder.ProfileLocked) + beholder.SendMessage("Your profile is locked. You may not change it."); else - from.Profile = e.Text; + beholder.Profile = text; } - public static void EventSink_ProfileRequest(ProfileRequestEventArgs e) + public static void EventSink_ProfileRequest(Mobile beholder, Mobile beheld) { - Mobile beholder = e.Beholder; - Mobile beheld = e.Beheld; - if (!beheld.Player) return; @@ -48,10 +43,7 @@ namespace Server.Misc if (footer.Length == 0 && beholder == beheld) footer = GetAccountDuration(beheld); - string body = beheld.Profile; - - if (body == null || body.Length <= 0) - body = ""; + string body = beheld.Profile ?? ""; beholder.Send(new DisplayProfile(beholder != beheld || !beheld.ProfileLocked, beheld, header, body, footer)); } @@ -90,4 +82,4 @@ namespace Server.Misc return false; } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/RenameRequests.cs b/Projects/Scripts/Misc/RenameRequests.cs index 02028eb0a..0dbd16b3c 100644 --- a/Projects/Scripts/Misc/RenameRequests.cs +++ b/Projects/Scripts/Misc/RenameRequests.cs @@ -1,18 +1,14 @@ namespace Server.Misc { - public class RenameRequests + public static class RenameRequests { public static void Initialize() { EventSink.RenameRequest += EventSink_RenameRequest; } - private static void EventSink_RenameRequest(RenameRequestEventArgs e) + private static void EventSink_RenameRequest(Mobile from, Mobile targ, string name) { - Mobile from = e.From; - Mobile targ = e.Target; - string name = e.Name; - if (from.CanSee(targ) && from.InRange(targ, 12) && targ.CanBeRenamedBy(from)) { name = name.Trim(); @@ -44,4 +40,4 @@ namespace Server.Misc } } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Misc/ShardPoller.cs b/Projects/Scripts/Misc/ShardPoller.cs index 7d0a7b84d..19ea08382 100644 --- a/Projects/Scripts/Misc/ShardPoller.cs +++ b/Projects/Scripts/Misc/ShardPoller.cs @@ -142,12 +142,12 @@ namespace Server.Misc EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs e) + private static void EventSink_Login(Mobile m) { if (m_ActivePollers.Count == 0) return; - Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, e.Mobile); + Timer.DelayCall(TimeSpan.FromSeconds(1.0), EventSink_Login_Callback, m); } private static void EventSink_Login_Callback(Mobile from) diff --git a/Projects/Scripts/Misc/WeightOverloading.cs b/Projects/Scripts/Misc/WeightOverloading.cs index 27704df0a..ed2f5924e 100644 --- a/Projects/Scripts/Misc/WeightOverloading.cs +++ b/Projects/Scripts/Misc/WeightOverloading.cs @@ -10,7 +10,7 @@ namespace Server.Misc PainSpike } - public class WeightOverloading + public static class WeightOverloading { public const int OverloadAllowance = 4; // We can be four stones overweight without getting fatigued @@ -117,4 +117,4 @@ namespace Server.Misc return Mobile.BodyWeight + m.TotalWeight > GetMaxWeight(m) + OverloadAllowance; } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Mobiles/AI/MageAI.cs b/Projects/Scripts/Mobiles/AI/MageAI.cs index e4f9e69a5..2673d6a4c 100644 --- a/Projects/Scripts/Mobiles/AI/MageAI.cs +++ b/Projects/Scripts/Mobiles/AI/MageAI.cs @@ -632,7 +632,7 @@ namespace Server.Mobiles if (!Core.AOS && SmartAI && !m_Mobile.StunReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && m_Mobile.Skills.Anatomy.Value >= 80.0) - EventSink.InvokeStunRequest(new StunRequestEventArgs(m_Mobile)); + EventSink.InvokeStunRequest(m_Mobile); if (!m_Mobile.InRange(c, m_Mobile.RangePerception)) { diff --git a/Projects/Scripts/Mobiles/AI/ThiefAI.cs b/Projects/Scripts/Mobiles/AI/ThiefAI.cs index 552ab0610..1d8716ed5 100644 --- a/Projects/Scripts/Mobiles/AI/ThiefAI.cs +++ b/Projects/Scripts/Mobiles/AI/ThiefAI.cs @@ -56,7 +56,7 @@ namespace Server.Mobiles if (!Core.AOS && !m_Mobile.DisarmReady && m_Mobile.Skills.Wrestling.Value >= 80.0 && m_Mobile.Skills.ArmsLore.Value >= 80.0 && m_toDisarm != null) - EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(m_Mobile)); + EventSink.InvokeDisarmRequest(m_Mobile); if (m_toDisarm?.IsChildOf(combatant.Backpack) == true && Core.TickCount - m_Mobile.NextSkillTime >= 0 && m_toDisarm.LootType != LootType.Blessed && diff --git a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs index 3c9e56c15..4d1fc3a75 100644 --- a/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs +++ b/Projects/Scripts/Mobiles/Monsters/Humanoid/Melee/KhaldunRevenant.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Server.Items; namespace Server.Mobiles @@ -71,21 +72,16 @@ namespace Server.Mobiles EventSink.PlayerDeath += EventSink_PlayerDeath; } - public static void EventSink_PlayerDeath(PlayerDeathEventArgs e) + public static void EventSink_PlayerDeath(Mobile m) { - Mobile m = e.Mobile; Mobile lastKiller = m.LastKiller; if (lastKiller is BaseCreature creature) lastKiller = creature.GetMaster(); - if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller)) - foreach (AggressorInfo ai in m.Aggressors) - if (ai.Attacker == lastKiller && ai.CanReportMurder) - { - SummonRevenant(m, lastKiller); - break; - } + if (IsInsideKhaldun(m) && IsInsideKhaldun(lastKiller) && lastKiller.Player && !m_Set.Contains(lastKiller) && + m.Aggressors.Any(ai => ai.Attacker == lastKiller && ai.CanReportMurder)) + SummonRevenant(m, lastKiller); } public static void SummonRevenant(Mobile victim, Mobile killer) diff --git a/Projects/Scripts/Mobiles/PlayerMobile.cs b/Projects/Scripts/Mobiles/PlayerMobile.cs index 6cc700f41..dbc0134d6 100644 --- a/Projects/Scripts/Mobiles/PlayerMobile.cs +++ b/Projects/Scripts/Mobiles/PlayerMobile.cs @@ -543,9 +543,76 @@ namespace Server.Mobiles EventSink.Connected += EventSink_Connected; EventSink.Disconnected += EventSink_Disconnected; + EventSink.TargetedSkillUse += TargetedSkillUse; + EventSink.EquipMacro += EquipMacro; + EventSink.UnequipMacro += UnequipMacro; + if (Core.SE) Timer.DelayCall(TimeSpan.Zero, CheckPets); } + private static void TargetedSkillUse(Mobile from, IEntity target, int skillId) + { + if (from == null || target == null) + return; + + from.TargetLocked = true; + + if (skillId == 35) + AnimalTaming.DisableMessage = true; + // AnimalTaming.DeferredTarget = false; + + if (from.UseSkill(skillId)) + from.Target?.Invoke(from, target); + + if (skillId == 35) + // AnimalTaming.DeferredTarget = true; + AnimalTaming.DisableMessage = false; + + from.TargetLocked = false; + } + + public static void EquipMacro(Mobile m, List list) + { + if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) + { + Container pack = pm.Backpack; + + foreach (var serial in list) + { + Item item = pack.Items.FirstOrDefault(i => i.Serial == serial); + if (item == null) continue; + + Item toMove = pm.FindItemOnLayer(item.Layer); + + if (toMove != null) + { + //pack.DropItem(toMove); + toMove.Internalize(); + + if (!pm.EquipItem(item)) + pm.EquipItem(toMove); + else + pack.DropItem(toMove); + } + else + pm.EquipItem(item); + } + } + } + + public static void UnequipMacro(Mobile m, List layers) + { + if (m is PlayerMobile pm && pm.Backpack != null && pm.Alive) + { + Container pack = pm.Backpack; + List eq = m.Items; + + foreach (var item in eq) + if (layers.Contains(item.Layer)) + pack.TryDropItem(pm, item, false); + } + } + private static void CheckPets() { foreach (Mobile m in World.Mobiles.Values) @@ -666,10 +733,8 @@ namespace Server.Mobiles SpecialMove.ClearCurrentMove(this); } - private static void OnLogin(LoginEventArgs e) + private static void OnLogin(Mobile from) { - Mobile from = e.Mobile; - CheckAtrophies(from); if (AccountHandler.LockdownLevel > AccessLevel.Player) @@ -925,15 +990,14 @@ namespace Server.Mobiles ValidateEquipment(); } - private static void OnLogout(LogoutEventArgs e) + private static void OnLogout(Mobile m) { - if (e.Mobile is PlayerMobile mobile) - mobile.AutoStablePets(); + (m as PlayerMobile)?.AutoStablePets(); } - private static void EventSink_Connected(ConnectedEventArgs e) + private static void EventSink_Connected(Mobile m) { - if (e.Mobile is PlayerMobile pm) + if (m is PlayerMobile pm) { pm.SessionStart = DateTime.UtcNow; @@ -943,14 +1007,13 @@ namespace Server.Mobiles pm.LastOnline = DateTime.UtcNow; } - DisguiseTimers.StartTimer(e.Mobile); + DisguiseTimers.StartTimer(m); - Timer.DelayCall(TimeSpan.Zero, SpecialMove.ClearAllMoves, e.Mobile); + Timer.DelayCall(TimeSpan.Zero, SpecialMove.ClearAllMoves, m); } - private static void EventSink_Disconnected(DisconnectedEventArgs e) + private static void EventSink_Disconnected(Mobile from) { - Mobile from = e.Mobile; DesignContext context = DesignContext.Find(from); if (context != null) @@ -977,7 +1040,7 @@ namespace Server.Mobiles context.Foundation.RestoreRelocatedEntities(); } - if (e.Mobile is PlayerMobile pm) + if (from is PlayerMobile pm) { pm.m_GameTime += DateTime.UtcNow - pm.SessionStart; diff --git a/Projects/Scripts/Multis/Boats/BaseBoat.cs b/Projects/Scripts/Multis/Boats/BaseBoat.cs index 1e992560c..2b0b00ce5 100644 --- a/Projects/Scripts/Multis/Boats/BaseBoat.cs +++ b/Projects/Scripts/Multis/Boats/BaseBoat.cs @@ -1650,7 +1650,7 @@ namespace Server.Multis EventSink.WorldSave += EventSink_WorldSave; } - private static void EventSink_WorldSave(WorldSaveEventArgs e) + private static void EventSink_WorldSave(bool message) { new UpdateAllTimer().Start(); } diff --git a/Projects/Scripts/Multis/Boats/Strandedness.cs b/Projects/Scripts/Multis/Boats/Strandedness.cs index 5f818ecee..b758cb6e1 100644 --- a/Projects/Scripts/Multis/Boats/Strandedness.cs +++ b/Projects/Scripts/Multis/Boats/Strandedness.cs @@ -115,10 +115,8 @@ namespace Server.Misc return false; } - public static void EventSink_Login(LoginEventArgs e) + public static void EventSink_Login(Mobile from) { - Mobile from = e.Mobile; - if (!IsStranded(from)) return; @@ -153,7 +151,7 @@ namespace Server.Misc int x = p.X, y = p.Y; int z; - bool canFit = false; + bool canFit; z = map.GetAverageZ(x, y); canFit = map.CanSpawnMobile(x, y, z); @@ -175,4 +173,4 @@ namespace Server.Misc from.Location = new Point3D(x, y, z); } } -} \ No newline at end of file +} diff --git a/Projects/Scripts/Multis/HouseFoundation.cs b/Projects/Scripts/Multis/HouseFoundation.cs index 568fc39a8..5a44ddc72 100644 --- a/Projects/Scripts/Multis/HouseFoundation.cs +++ b/Projects/Scripts/Multis/HouseFoundation.cs @@ -1745,7 +1745,7 @@ namespace Server.Multis Fixtures[i].m_OffsetX = reader.ReadShort(); Fixtures[i].m_OffsetY = reader.ReadShort(); Fixtures[i].m_OffsetZ = reader.ReadShort(); - Fixtures[i].m_Flags = reader.ReadInt(); + Fixtures[i].m_Flags = (TileFlag)reader.ReadInt(); } Revision = reader.ReadInt(); @@ -1793,7 +1793,7 @@ namespace Server.Multis writer.Write(ent.m_OffsetX); writer.Write(ent.m_OffsetY); writer.Write(ent.m_OffsetZ); - writer.Write(ent.m_Flags); + writer.Write((int)ent.m_Flags); } writer.Write(Revision); diff --git a/Projects/Scripts/Regions/HouseRegion.cs b/Projects/Scripts/Regions/HouseRegion.cs index 46a4d99b9..9413238f5 100644 --- a/Projects/Scripts/Regions/HouseRegion.cs +++ b/Projects/Scripts/Regions/HouseRegion.cs @@ -30,12 +30,12 @@ namespace Server.Regions EventSink.Login += OnLogin; } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - BaseHouse house = BaseHouse.FindHouseAt(e.Mobile); + BaseHouse house = BaseHouse.FindHouseAt(m); - if (house?.Public == false && !house.IsFriend(e.Mobile)) - e.Mobile.Location = house.BanLocation; + if (house?.Public == false && !house.IsFriend(m)) + m.Location = house.BanLocation; } public override bool AllowHousing(Mobile from, Point3D p) => false; diff --git a/Projects/Scripts/Scripts.csproj b/Projects/Scripts/Scripts.csproj index 670d74678..bc6751c31 100644 --- a/Projects/Scripts/Scripts.csproj +++ b/Projects/Scripts/Scripts.csproj @@ -35,7 +35,7 @@ - + diff --git a/Projects/Scripts/SpecialSystems/Engines/GiftGiving.cs b/Projects/Scripts/SpecialSystems/Engines/GiftGiving.cs index 2d3819f47..483c0b0b0 100644 --- a/Projects/Scripts/SpecialSystems/Engines/GiftGiving.cs +++ b/Projects/Scripts/SpecialSystems/Engines/GiftGiving.cs @@ -24,9 +24,9 @@ namespace Server.Misc EventSink.Login += EventSink_Login; } - private static void EventSink_Login(LoginEventArgs e) + private static void EventSink_Login(Mobile m) { - if (!(e.Mobile.Account is Account acct)) + if (!(m.Account is Account acct)) return; DateTime now = DateTime.UtcNow; @@ -44,7 +44,7 @@ namespace Server.Misc if (acct.LastLogin >= giver.Start) continue; // already got one - giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), e.Mobile); + giver.DelayGiveGift(TimeSpan.FromSeconds(5.0), m); } acct.LastLogin = now; diff --git a/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs b/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs index 9e25a137f..e6477956c 100644 --- a/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs +++ b/Projects/Scripts/SpecialSystems/Engines/PreventInaccess.cs @@ -37,10 +37,8 @@ namespace Server.Misc EventSink.Login += OnLogin; } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile from) { - Mobile from = e.Mobile; - if (from == null || from.AccessLevel < AccessLevel.Counselor) return; diff --git a/Projects/Scripts/Spells/Mysticism/SpellPlagueSpell.cs b/Projects/Scripts/Spells/Mysticism/SpellPlagueSpell.cs index dc938ac55..3d7a25653 100644 --- a/Projects/Scripts/Spells/Mysticism/SpellPlagueSpell.cs +++ b/Projects/Scripts/Spells/Mysticism/SpellPlagueSpell.cs @@ -93,9 +93,9 @@ namespace Server.Spells.Mysticism context.OnDamage(); } - private static void OnPlayerDeath(PlayerDeathEventArgs e) + private static void OnPlayerDeath(Mobile m) { - RemoveEffect(e.Mobile); + RemoveEffect(m); } protected void VisualEffect(Mobile to) diff --git a/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs b/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs index d3ede2835..d201509df 100644 --- a/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs +++ b/Projects/Scripts/Spells/Mysticism/StoneFormSpell.cs @@ -146,9 +146,9 @@ namespace Server.Spells.Mysticism BuffInfo.RemoveBuff(m, BuffIcon.StoneForm); } - private static void OnPlayerDeath(PlayerDeathEventArgs e) + private static void OnPlayerDeath(Mobile m) { - RemoveEffects(e.Mobile); + RemoveEffects(m); } } } diff --git a/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs b/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs index 96711d893..e35548464 100644 --- a/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs +++ b/Projects/Scripts/Spells/Ninjitsu/AnimalForm.cs @@ -67,10 +67,10 @@ namespace Server.Spells.Ninjitsu EventSink.Login += OnLogin; } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - if (GetContext(e.Mobile)?.SpeedBoost == true) - e.Mobile.Send(SpeedControl.MountSpeed); + if (GetContext(m)?.SpeedBoost == true) + m.Send(SpeedControl.MountSpeed); } public override bool CheckCast() diff --git a/Projects/Scripts/Spells/Spellweaving/EtherealVoyage.cs b/Projects/Scripts/Spells/Spellweaving/EtherealVoyage.cs index 8e86426f6..acf1bfad1 100644 --- a/Projects/Scripts/Spells/Spellweaving/EtherealVoyage.cs +++ b/Projects/Scripts/Spells/Spellweaving/EtherealVoyage.cs @@ -24,11 +24,13 @@ namespace Server.Spells.Spellweaving public static void Initialize() { - EventSink.AggressiveAction += delegate(AggressiveActionEventArgs e) - { - if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell))) - TransformationSpellHelper.RemoveContext(e.Aggressor, true); - }; + EventSink.AggressiveAction += RemoveTransformationOnAggressiveAction; + } + + public static void RemoveTransformationOnAggressiveAction(AggressiveActionEventArgs e) + { + if (TransformationSpellHelper.UnderTransformation(e.Aggressor, typeof(EtherealVoyageSpell))) + TransformationSpellHelper.RemoveContext(e.Aggressor, true); } public override bool CheckCast() diff --git a/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs b/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs index f04154d49..7a77fd28f 100644 --- a/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs +++ b/Projects/Scripts/Spells/Spellweaving/GiftOfLife.cs @@ -29,7 +29,7 @@ namespace Server.Spells.Spellweaving public static void Initialize() { - EventSink.PlayerDeath += delegate(PlayerDeathEventArgs e) { HandleDeath(e.Mobile); }; + EventSink.PlayerDeath += HandleDeath; } public override void OnCast() @@ -132,10 +132,8 @@ namespace Server.Spells.Spellweaving timer.DoExpire(); } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - Mobile m = e.Mobile; - if (m?.Alive != false || m_Table[m] == null) return; diff --git a/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs b/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs index ff693ec24..120f38e82 100644 --- a/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs +++ b/Projects/Scripts/Spells/Spellweaving/ReaperForm.cs @@ -32,12 +32,12 @@ namespace Server.Spells.Spellweaving EventSink.Login += OnLogin; } - public static void OnLogin(LoginEventArgs e) + public static void OnLogin(Mobile m) { - TransformContext context = TransformationSpellHelper.GetContext(e.Mobile); + TransformContext context = TransformationSpellHelper.GetContext(m); if (context?.Type == typeof(ReaperFormSpell)) - e.Mobile.Send(SpeedControl.WalkSpeed); + m.Send(SpeedControl.WalkSpeed); } public override void DoEffect(Mobile m) diff --git a/Projects/Server/AssemblyHandler.cs b/Projects/Server/AssemblyHandler.cs index 31bba7e48..8a06aca79 100644 --- a/Projects/Server/AssemblyHandler.cs +++ b/Projects/Server/AssemblyHandler.cs @@ -68,6 +68,7 @@ namespace Server var types = FindTypesByName(name, ignoreCase).ToList(); if (types.Count == 0) return null; + if (predicate != null) return types.FirstOrDefault(predicate); if (types.Count == 1) @@ -76,10 +77,13 @@ namespace Server // Check for exact match of the FullName or Name // Then check for case-insensitive match of FullName or Name // Otherwise just return the first entry - return (!ignoreCase ? types.FirstOrDefault(x => x.FullName == name || x.Name == name) : null) - ?? types.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.FullName, name) || StringComparer.OrdinalIgnoreCase.Equals(x.Name, name)) - ?? types[0]; + var stringComparer = ignoreCase ? StringComparer.OrdinalIgnoreCase : StringComparer.Ordinal; + + return types.FirstOrDefault(x => + stringComparer.Equals(x.FullName, name) || stringComparer.Equals(x.Name, name)) ?? + types[0]; } + public static IEnumerable FindTypesByName(string name, bool ignoreCase = false) { List types = new List(); @@ -122,31 +126,30 @@ namespace Server refs.Add(index); else { - refs = new HashSet(); - refs.Add(index); + refs = new HashSet {index}; nameMap.Add(key, refs); } }; Type current; Type aliasType = typeof(TypeAliasAttribute); TypeAliasAttribute alias; - for (int i = 0, j = 0; i < m_Types.Length; i++) + for (int i = 0; i < m_Types.Length; i++) { current = m_Types[i]; addToRefs(i, current.Name); addToRefs(i, current.Name.ToLower()); addToRefs(i, current.FullName); - addToRefs(i, current.FullName.ToLower()); + addToRefs(i, current.FullName?.ToLower()); alias = current.GetCustomAttribute(aliasType, false) as TypeAliasAttribute; if (alias != null) - for (j = 0; j < alias.Aliases.Length; j++) + for (int j = 0; j < alias.Aliases.Length; j++) { addToRefs(i, alias.Aliases[j]); addToRefs(i, alias.Aliases[j].ToLower()); } } - foreach (var entry in nameMap) - m_NameMap[entry.Key] = entry.Value.ToArray(); + foreach (var (key, value) in nameMap) + m_NameMap[key] = value.ToArray(); } } } diff --git a/Projects/Server/Buffers/BufferReader.cs b/Projects/Server/Buffers/BufferReader.cs new file mode 100644 index 000000000..bc6f93eb6 --- /dev/null +++ b/Projects/Server/Buffers/BufferReader.cs @@ -0,0 +1,314 @@ +// Copyright (c) Harry Pierson. All rights reserved. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Threading; + +namespace System.Buffers +{ + public ref struct BufferReader + { + private readonly bool usingSequence; + private readonly ReadOnlySequence sequence; + private SequencePosition currentPosition; + private SequencePosition nextPosition; + private bool moreData; + private readonly long length; + + public BufferReader(ReadOnlySpan span) + { + usingSequence = false; + CurrentSpanIndex = 0; + Consumed = 0; + sequence = default; + currentPosition = default; + length = span.Length; + + CurrentSpan = span; + nextPosition = default; + moreData = span.Length > 0; + } + + public BufferReader(in ReadOnlySequence sequence) + { + usingSequence = true; + CurrentSpanIndex = 0; + Consumed = 0; + this.sequence = sequence; + currentPosition = sequence.Start; + length = -1; + + var first = sequence.First.Span; + CurrentSpan = first; + nextPosition = sequence.GetPosition(first.Length); + moreData = first.Length > 0; + + if (!moreData && !sequence.IsSingleSegment) + { + moreData = true; + GetNextSpan(); + } + } + + public readonly bool End => !moreData; + + public ReadOnlySpan CurrentSpan { get; private set; } + + public int CurrentSpanIndex { get; private set; } + + public readonly ReadOnlySpan UnreadSpan + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => CurrentSpan.Slice(CurrentSpanIndex); + } + + public long Consumed { get; private set; } + + public readonly long Remaining => Length - Consumed; + + public readonly long Length + { + get + { + if (length < 0) + { + Debug.Assert(usingSequence, "usingSequence"); + // Cast-away readonly to initialize lazy field + Volatile.Write(ref Unsafe.AsRef(length), sequence.Length); + } + return length; + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool TryPeek([MaybeNullWhen(false)] out T value) + { + if (moreData) + { + value = CurrentSpan[CurrentSpanIndex]; + return true; + } + + value = default!; + return false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool TryRead([MaybeNullWhen(false)] out T value) + { + if (End) + { + value = default!; + return false; + } + + value = CurrentSpan[CurrentSpanIndex]; + CurrentSpanIndex++; + Consumed++; + + if (CurrentSpanIndex >= CurrentSpan.Length) + { + if (usingSequence) + GetNextSpan(); + else + moreData = false; + } + + return true; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Rewind(long count) + { + if ((ulong)count > (ulong)Consumed) throw new ArgumentOutOfRangeException(nameof(count)); + + Consumed -= count; + + if (CurrentSpanIndex >= count) + { + CurrentSpanIndex -= (int)count; + moreData = true; + } + else if (usingSequence) + { + // Current segment doesn't have enough data, scan backward through segments + RetreatToPreviousSpan(Consumed); + } + else + { + throw new ArgumentOutOfRangeException($"Rewind went past the start of the memory by {count}.", nameof(count)); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private void RetreatToPreviousSpan(long consumed) + { + Debug.Assert(usingSequence, "usingSequence"); + ResetReader(); + Advance(consumed); + } + + private void ResetReader() + { + Debug.Assert(usingSequence, "usingSequence"); + CurrentSpanIndex = 0; + Consumed = 0; + currentPosition = sequence.Start; + nextPosition = currentPosition; + + if (sequence.TryGet(ref nextPosition, out ReadOnlyMemory memory)) + { + moreData = true; + + if (memory.Length == 0) + { + CurrentSpan = default; + // No data in the first span, move to one with data + GetNextSpan(); + } + else + { + CurrentSpan = memory.Span; + } + } + else + { + // No data in any spans and at end of sequence + moreData = false; + CurrentSpan = default; + } + } + + private void GetNextSpan() + { + Debug.Assert(usingSequence, "usingSequence"); + if (!sequence.IsSingleSegment) + { + SequencePosition previousNextPosition = nextPosition; + while (sequence.TryGet(ref nextPosition, out ReadOnlyMemory memory)) + { + currentPosition = previousNextPosition; + if (memory.Length > 0) + { + CurrentSpan = memory.Span; + CurrentSpanIndex = 0; + return; + } + + CurrentSpan = default; + CurrentSpanIndex = 0; + previousNextPosition = nextPosition; + } + } + moreData = false; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(long count) + { + const long TooBigOrNegative = unchecked((long)0xFFFFFFFF80000000); + if ((count & TooBigOrNegative) == 0 && CurrentSpan.Length - CurrentSpanIndex > (int)count) + { + CurrentSpanIndex += (int)count; + Consumed += count; + } + else if (usingSequence) + { + // Can't satisfy from the current span + AdvanceToNextSpan(count); + } + else if (CurrentSpan.Length - CurrentSpanIndex == (int)count) + { + CurrentSpanIndex += (int)count; + Consumed += count; + moreData = false; + } + else + { + throw new ArgumentOutOfRangeException(nameof(count)); + } + } + + private void AdvanceToNextSpan(long count) + { + Debug.Assert(usingSequence, "usingSequence"); + if (count < 0) throw new ArgumentOutOfRangeException(nameof(count)); + + Consumed += count; + while (moreData) + { + int remaining = CurrentSpan.Length - CurrentSpanIndex; + + if (remaining > count) + { + CurrentSpanIndex += (int)count; + count = 0; + break; + } + + // As there may not be any further segments we need to + // push the current index to the end of the span. + CurrentSpanIndex += remaining; + count -= remaining; + Debug.Assert(count >= 0); + + GetNextSpan(); + + if (count == 0) break; + } + + if (count != 0) + { + // Not enough data left- adjust for where we actually ended and throw + Consumed -= count; + throw new ArgumentOutOfRangeException(nameof(count)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly bool TryCopyTo(Span destination) + { + // This API doesn't advance to facilitate conditional advancement based on the data returned. + // We don't provide an advance option to allow easier utilizing of stack allocated destination spans. + // (Because we can make this method readonly we can guarantee that we won't capture the span.) + + ReadOnlySpan firstSpan = UnreadSpan; + if (firstSpan.Length >= destination.Length) + { + firstSpan.Slice(0, destination.Length).CopyTo(destination); + return true; + } + + // Not enough in the current span to satisfy the request, fall through to the slow path + return TryCopyMultisegment(destination); + } + + internal readonly bool TryCopyMultisegment(Span destination) + { + // If we don't have enough to fill the requested buffer, return false + if (Remaining < destination.Length) + return false; + + ReadOnlySpan firstSpan = UnreadSpan; + Debug.Assert(firstSpan.Length < destination.Length); + firstSpan.CopyTo(destination); + int copied = firstSpan.Length; + + SequencePosition next = nextPosition; + while (sequence.TryGet(ref next, out ReadOnlyMemory nextSegment)) + if (nextSegment.Length > 0) + { + ReadOnlySpan nextSpan = nextSegment.Span; + int toCopy = Math.Min(nextSpan.Length, destination.Length - copied); + nextSpan.Slice(0, toCopy).CopyTo(destination.Slice(copied)); + copied += toCopy; + if (copied >= destination.Length) break; + } + + return true; + } + } +} diff --git a/Projects/Server/Buffers/BufferReaderExtensions.cs b/Projects/Server/Buffers/BufferReaderExtensions.cs new file mode 100644 index 000000000..0365f02db --- /dev/null +++ b/Projects/Server/Buffers/BufferReaderExtensions.cs @@ -0,0 +1,181 @@ +// Copyright (c) Harry Pierson. All rights reserved. +// Licensed under the MIT license. +// See LICENSE file in the project root for full license information. + +using System.Buffers.Binary; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace System.Buffers +{ + public static class BufferReaderExtensions + { + private static unsafe bool TryRead(ref this BufferReader reader, out T value) + where T : unmanaged + { + ReadOnlySpan span = reader.UnreadSpan; + if (span.Length < sizeof(T)) return TryReadMultisegment(ref reader, out value); + + value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(span)); + reader.Advance(sizeof(T)); + return true; + } + + private static unsafe bool TryReadMultisegment(ref BufferReader reader, out T value) + where T : unmanaged + { + Debug.Assert(reader.UnreadSpan.Length < sizeof(T), "reader.UnreadSpan.Length < sizeof(T)"); + + // Not enough data in the current segment, try to peek for the data we need. + T buffer = default; + Span tempSpan = new Span(&buffer, sizeof(T)); + + if (!reader.TryCopyTo(tempSpan)) + { + value = default; + return false; + } + + value = Unsafe.ReadUnaligned(ref MemoryMarshal.GetReference(tempSpan)); + reader.Advance(sizeof(T)); + return true; + } + + public static bool TryRead(ref this BufferReader reader, out sbyte value) + { + if (TryRead(ref reader, out byte byteValue)) + { + value = unchecked((sbyte)byteValue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadLittleEndian(ref this BufferReader reader, out short value) => + BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + public static bool TryReadBigEndian(ref this BufferReader reader, out short value) => + !BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + private static bool TryReadReverseEndianness(ref BufferReader reader, out short value) + { + if (reader.TryRead(out value)) + { + value = BinaryPrimitives.ReverseEndianness(value); + return true; + } + + return false; + } + + public static bool TryReadLittleEndian(ref this BufferReader reader, out ushort value) + { + if (TryReadLittleEndian(ref reader, out short signedvalue)) + { + value = unchecked((ushort)signedvalue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadBigEndian(ref this BufferReader reader, out ushort value) + { + if (TryReadBigEndian(ref reader, out short signedvalue)) + { + value = unchecked((ushort)signedvalue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadLittleEndian(ref this BufferReader reader, out int value) => + BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + public static bool TryReadBigEndian(ref this BufferReader reader, out int value) => + !BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + private static bool TryReadReverseEndianness(ref BufferReader reader, out int value) + { + if (reader.TryRead(out value)) + { + value = BinaryPrimitives.ReverseEndianness(value); + return true; + } + + return false; + } + + public static bool TryReadLittleEndian(ref this BufferReader reader, out uint value) + { + if (TryReadLittleEndian(ref reader, out int signedvalue)) + { + value = unchecked((uint)signedvalue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadBigEndian(ref this BufferReader reader, out uint value) + { + if (TryReadBigEndian(ref reader, out int signedvalue)) + { + value = unchecked((uint)signedvalue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadLittleEndian(ref this BufferReader reader, out long value) => + BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + public static bool TryReadBigEndian(ref this BufferReader reader, out long value) => + !BitConverter.IsLittleEndian ? reader.TryRead(out value) : TryReadReverseEndianness(ref reader, out value); + + private static bool TryReadReverseEndianness(ref BufferReader reader, out long value) + { + if (reader.TryRead(out value)) + { + value = BinaryPrimitives.ReverseEndianness(value); + return true; + } + + return false; + } + + + public static bool TryReadLittleEndian(ref this BufferReader reader, out ulong value) + { + if (TryReadLittleEndian(ref reader, out long signedvalue)) + { + value = unchecked((ulong)signedvalue); + return true; + } + + value = default; + return false; + } + + public static bool TryReadBigEndian(ref this BufferReader reader, out ulong value) + { + if (TryReadBigEndian(ref reader, out long signedvalue)) + { + value = unchecked((ulong)signedvalue); + return true; + } + + value = default; + return false; + } + } +} diff --git a/Projects/Server/Buffers/BufferWriter.cs b/Projects/Server/Buffers/BufferWriter.cs new file mode 100644 index 000000000..c534a238f --- /dev/null +++ b/Projects/Server/Buffers/BufferWriter.cs @@ -0,0 +1,143 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System.Runtime.CompilerServices; + +namespace System.Buffers +{ + /// + /// A fast access struct that wraps . + /// + /// The type of element to be written. + internal ref struct BufferWriter where T : IBufferWriter + { + /// + /// The underlying . + /// + private T _output; + + /// + /// The result of the last call to , less any bytes already "consumed" with . + /// Backing field for the property. + /// + private Span _span; + + /// + /// The number of uncommitted bytes (all the calls to since the last call to ). + /// + private int _buffered; + + /// + /// The total number of bytes written with this writer. + /// Backing field for the property. + /// + private long _bytesCommitted; + + /// + /// Initializes a new instance of the struct. + /// + /// The to be wrapped. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public BufferWriter(T output) + { + _buffered = 0; + _bytesCommitted = 0; + _output = output; + _span = output.GetSpan(); + } + + /// + /// Gets the result of the last call to . + /// + public Span Span => _span; + + /// + /// Gets the total number of bytes written with this writer. + /// + public long BytesCommitted => _bytesCommitted; + + /// + /// Calls on the underlying writer + /// with the number of uncommitted bytes. + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Commit() + { + var buffered = _buffered; + if (buffered > 0) + { + _bytesCommitted += buffered; + _buffered = 0; + _output.Advance(buffered); + } + } + + /// + /// Used to indicate that part of the buffer has been written to. + /// + /// The number of bytes written to. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Advance(int count) + { + _buffered += count; + _span = _span.Slice(count); + } + + /// + /// Copies the caller's buffer into this writer and calls with the length of the source buffer. + /// + /// The buffer to copy in. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Write(ReadOnlySpan source) + { + if (_span.Length >= source.Length) + { + source.CopyTo(_span); + Advance(source.Length); + } + else + { + WriteMultiBuffer(source); + } + } + + /// + /// Acquires a new buffer if necessary to ensure that some given number of bytes can be written to a single buffer. + /// + /// The number of bytes that must be allocated in a single buffer. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void Ensure(int count = 1) + { + if (_span.Length < count) EnsureMore(count); + } + + /// + /// Gets a fresh span to write to, with an optional minimum size. + /// + /// The minimum size for the next requested buffer. + [MethodImpl(MethodImplOptions.NoInlining)] + private void EnsureMore(int count = 0) + { + if (_buffered > 0) Commit(); + + _span = _output.GetSpan(count); + } + + /// + /// Copies the caller's buffer into this writer, potentially across multiple buffers from the underlying writer. + /// + /// The buffer to copy into this writer. + private void WriteMultiBuffer(ReadOnlySpan source) + { + while (source.Length > 0) + { + if (_span.Length == 0) EnsureMore(); + + var writable = Math.Min(source.Length, _span.Length); + source.Slice(0, writable).CopyTo(_span); + source = source.Slice(writable); + Advance(writable); + } + } + } +} diff --git a/Projects/Server/Buffers/DiagnosticMemoryPool.cs b/Projects/Server/Buffers/DiagnosticMemoryPool.cs deleted file mode 100644 index 9f032a571..000000000 --- a/Projects/Server/Buffers/DiagnosticMemoryPool.cs +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Collections.Generic; -using System.Linq; -using System.Threading.Tasks; - -namespace System.Buffers -{ - /// - /// Used to allocate and distribute re-usable blocks of memory. - /// - public class DiagnosticMemoryPool : MemoryPool - { - private readonly MemoryPool _pool; - - private readonly bool _allowLateReturn; - - private readonly bool _rentTracking; - - private readonly object _syncObj; - - private readonly HashSet _blocks; - - private readonly List _blockAccessExceptions; - - private readonly TaskCompletionSource _allBlocksReturned; - - private int _totalBlocks; - - /// - /// This default value passed in to Rent to use the default value for the pool. - /// - private const int AnySize = -1; - - public DiagnosticMemoryPool(MemoryPool pool, bool allowLateReturn = false, bool rentTracking = false) - { - _pool = pool; - _allowLateReturn = allowLateReturn; - _rentTracking = rentTracking; - _blocks = new HashSet(); - _syncObj = new object(); - _allBlocksReturned = new TaskCompletionSource(TaskCreationOptions.RunContinuationsAsynchronously); - _blockAccessExceptions = new List(); - } - - public bool IsDisposed { get; private set; } - - public override IMemoryOwner Rent(int size = AnySize) - { - lock (_syncObj) - { - if (IsDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPool); - - var diagnosticPoolBlock = new DiagnosticPoolBlock(this, _pool.Rent(size)); - if (_rentTracking) diagnosticPoolBlock.Track(); - _totalBlocks++; - _blocks.Add(diagnosticPoolBlock); - return diagnosticPoolBlock; - } - } - - public override int MaxBufferSize => _pool.MaxBufferSize; - - internal void Return(DiagnosticPoolBlock block) - { - bool returnedAllBlocks; - lock (_syncObj) - { - _blocks.Remove(block); - returnedAllBlocks = _blocks.Count == 0; - } - - if (IsDisposed) - { - if (!_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockReturnedToDisposedPool(block); - - if (returnedAllBlocks) SetAllBlocksReturned(); - } - - } - - internal void ReportException(Exception exception) - { - lock (_syncObj) - { - _blockAccessExceptions.Add(exception); - } - } - - protected override void Dispose(bool disposing) - { - if (IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_DoubleDispose(); - - bool allBlocksReturned = false; - try - { - lock (_syncObj) - { - IsDisposed = true; - allBlocksReturned = _blocks.Count == 0; - if (!allBlocksReturned && !_allowLateReturn) MemoryPoolThrowHelper.ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray()); - - if (_blockAccessExceptions.Any()) throw CreateAccessExceptions(); - } - } - finally - { - if (allBlocksReturned) SetAllBlocksReturned(); - } - } - - private void SetAllBlocksReturned() - { - if (_blockAccessExceptions.Any()) - _allBlocksReturned.SetException(CreateAccessExceptions()); - else - _allBlocksReturned.SetResult(null); - } - - private AggregateException CreateAccessExceptions() => new AggregateException("Exceptions occurred while accessing blocks", _blockAccessExceptions.ToArray()); - - public async Task WhenAllBlocksReturnedAsync(TimeSpan timeout) - { - var task = await Task.WhenAny(_allBlocksReturned.Task, Task.Delay(timeout)); - if (task != _allBlocksReturned.Task) - MemoryPoolThrowHelper.ThrowInvalidOperationException_BlocksWereNotReturnedInTime(_totalBlocks - _blocks.Count, _totalBlocks, _blocks.ToArray()); - - await task; - } - } -} diff --git a/Projects/Server/Buffers/DiagnosticPoolBlock.cs b/Projects/Server/Buffers/DiagnosticPoolBlock.cs deleted file mode 100644 index 62da1dc84..000000000 --- a/Projects/Server/Buffers/DiagnosticPoolBlock.cs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright (c) Microsoft. All rights reserved. -// Licensed under the MIT license. See LICENSE file in the project root for full license information. - -using System.Threading; -using System.Diagnostics; -using System.Runtime.InteropServices; - -namespace System.Buffers -{ - /// - /// Block tracking object used by the byte buffer memory pool. A slab is a large allocation which is divided into smaller blocks. The - /// individual blocks are then treated as independent array segments. - /// - public sealed class DiagnosticPoolBlock : MemoryManager - { - /// - /// Back-reference to the memory pool which this block was allocated from. It may only be returned to this pool. - /// - private readonly DiagnosticMemoryPool _pool; - - private readonly IMemoryOwner _memoryOwner; - private MemoryHandle? _memoryHandle; - private readonly Memory _memory; - - private readonly object _syncObj = new object(); - private bool _isDisposed; - private int _pinCount; - - - /// - /// This object cannot be instantiated outside of the static Create method - /// - internal DiagnosticPoolBlock(DiagnosticMemoryPool pool, IMemoryOwner memoryOwner) - { - _pool = pool; - _memoryOwner = memoryOwner; - _memory = memoryOwner.Memory; - } - - public override Memory Memory - { - get - { - try - { - lock (_syncObj) - { - if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock); - - if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this); - - return CreateMemory(_memory.Length); - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - } - - protected override void Dispose(bool disposing) - { - try - { - lock (_syncObj) - { - if (Volatile.Read(ref _pinCount) > 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_ReturningPinnedBlock(this); - - if (_isDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockDoubleDispose(this); - - _memoryOwner.Dispose(); - - _pool.Return(this); - - _isDisposed = true; - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - - public override Span GetSpan() - { - try - { - lock (_syncObj) - { - if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock); - - if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this); - - return _memory.Span; - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - - public override MemoryHandle Pin(int byteOffset = 0) - { - try - { - lock (_syncObj) - { - if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock); - - if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this); - - if (byteOffset < 0 || byteOffset > _memory.Length) MemoryPoolThrowHelper.ThrowArgumentOutOfRangeException(_memory.Length, byteOffset); - - _pinCount++; - - _memoryHandle ??= _memory.Pin(); - - unsafe - { - return new MemoryHandle(((IntPtr)_memoryHandle.Value.Pointer + byteOffset).ToPointer(), default, this); - } - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - - protected override bool TryGetArray(out ArraySegment segment) - { - try - { - lock (_syncObj) - { - if (_isDisposed) MemoryPoolThrowHelper.ThrowObjectDisposedException(MemoryPoolThrowHelper.ExceptionArgument.MemoryPoolBlock); - - if (_pool.IsDisposed) MemoryPoolThrowHelper.ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(this); - - return MemoryMarshal.TryGetArray(_memory, out segment); - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - - public override void Unpin() - { - try - { - lock (_syncObj) - { - if (_pinCount == 0) MemoryPoolThrowHelper.ThrowInvalidOperationException_PinCountZero(this); - - _pinCount--; - - if (_pinCount == 0) - { - Debug.Assert(_memoryHandle.HasValue); - _memoryHandle.Value.Dispose(); - _memoryHandle = null; - } - } - } - catch (Exception exception) - { - _pool.ReportException(exception); - throw; - } - } - - public StackTrace Leaser { get; set; } - - public void Track() - { - Leaser = new StackTrace(false); - } - } -} diff --git a/Projects/Server/Buffers/MemoryPoolThrowHelper.cs b/Projects/Server/Buffers/MemoryPoolThrowHelper.cs index cf6284148..c1ae51b7d 100644 --- a/Projects/Server/Buffers/MemoryPoolThrowHelper.cs +++ b/Projects/Server/Buffers/MemoryPoolThrowHelper.cs @@ -7,7 +7,7 @@ using System.Text; namespace System.Buffers { - public class MemoryPoolThrowHelper + public static class MemoryPoolThrowHelper { public static void ThrowArgumentOutOfRangeException(int sourceLength, int offset) { @@ -17,60 +17,6 @@ namespace System.Buffers [MethodImpl(MethodImplOptions.NoInlining)] private static ArgumentOutOfRangeException GetArgumentOutOfRangeException(int sourceLength, int offset) => (uint)offset > (uint)sourceLength ? new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.offset)) : new ArgumentOutOfRangeException(GetArgumentName(ExceptionArgument.length)); - public static void ThrowInvalidOperationException_PinCountZero(DiagnosticPoolBlock block) - { - throw new InvalidOperationException(GenerateMessage("Can't unpin, pin count is zero", block)); - } - - public static void ThrowInvalidOperationException_ReturningPinnedBlock(DiagnosticPoolBlock block) - { - throw new InvalidOperationException(GenerateMessage("Disposing pinned block", block)); - } - - public static void ThrowInvalidOperationException_DoubleDispose() - { - throw new InvalidOperationException("Object is being disposed twice"); - } - - public static void ThrowInvalidOperationException_BlockDoubleDispose(DiagnosticPoolBlock block) - { - throw new InvalidOperationException("Block is being disposed twice"); - } - - public static void ThrowInvalidOperationException_BlockReturnedToDisposedPool(DiagnosticPoolBlock block) - { - throw new InvalidOperationException(GenerateMessage("Block is being returned to disposed pool", block)); - } - - public static void ThrowInvalidOperationException_BlockIsBackedByDisposedSlab(DiagnosticPoolBlock block) - { - throw new InvalidOperationException(GenerateMessage("Block is backed by disposed slab", block)); - } - - public static void ThrowInvalidOperationException_DisposingPoolWithActiveBlocks(int returned, int total, DiagnosticPoolBlock[] blocks) - { - throw new InvalidOperationException(GenerateMessage($"Memory pool with active blocks is being disposed, {returned} of {total} returned", blocks)); - } - - public static void ThrowInvalidOperationException_BlocksWereNotReturnedInTime(int returned, int total, DiagnosticPoolBlock[] blocks) - { - throw new InvalidOperationException(GenerateMessage($"Blocks were not returned in time, {returned} of {total} returned ", blocks)); - } - - private static string GenerateMessage(string message, params DiagnosticPoolBlock[] blocks) - { - StringBuilder builder = new StringBuilder(message); - foreach (var diagnosticPoolBlock in blocks) - if (diagnosticPoolBlock.Leaser != null) - { - builder.AppendLine(); - - builder.AppendLine("Block leased from:"); - builder.AppendLine(diagnosticPoolBlock.Leaser.ToString()); - } - - return builder.ToString(); - } public static void ThrowArgumentOutOfRangeException_BufferRequestTooLarge(int maxSize) { diff --git a/Projects/Server/Commands.cs b/Projects/Server/Commands.cs index ec06e49c8..f9cd86ed4 100644 --- a/Projects/Server/Commands.cs +++ b/Projects/Server/Commands.cs @@ -95,6 +95,12 @@ namespace Server } } + public static partial class EventSink + { + public static event Action Command; + public static void InvokeCommand(CommandEventArgs e) => Command?.Invoke(e); + } + public class CommandEntry : IComparable { public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel) diff --git a/Projects/Server/EventSink.cs b/Projects/Server/EventSink.cs deleted file mode 100644 index a5a826932..000000000 --- a/Projects/Server/EventSink.cs +++ /dev/null @@ -1,1086 +0,0 @@ -/*************************************************************************** - * EventSink.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ - -using System; -using System.Collections.Generic; -using System.Net; -using Microsoft.AspNetCore.Connections; -using Server.Accounting; -using Server.Guilds; -using Server.Network; - -namespace Server -{ - public delegate void CharacterCreatedEventHandler(CharacterCreatedEventArgs e); - - public delegate void OpenDoorMacroEventHandler(OpenDoorMacroEventArgs e); - - public delegate void SpeechEventHandler(SpeechEventArgs e); - - public delegate void LoginEventHandler(LoginEventArgs e); - - public delegate void ServerListEventHandler(ServerListEventArgs e); - - public delegate void MovementEventHandler(MovementEventArgs e); - - public delegate void HungerChangedEventHandler(HungerChangedEventArgs e); - - public delegate void CrashedEventHandler(CrashedEventArgs e); - - public delegate void ShutdownEventHandler(ShutdownEventArgs e); - - public delegate void HelpRequestEventHandler(HelpRequestEventArgs e); - - public delegate void DisarmRequestEventHandler(DisarmRequestEventArgs e); - - public delegate void StunRequestEventHandler(StunRequestEventArgs e); - - public delegate void OpenSpellbookRequestEventHandler(OpenSpellbookRequestEventArgs e); - - public delegate void CastSpellRequestEventHandler(CastSpellRequestEventArgs e); - - public delegate void BandageTargetRequestEventHandler(BandageTargetRequestEventArgs e); - - public delegate void AnimateRequestEventHandler(AnimateRequestEventArgs e); - - public delegate void LogoutEventHandler(LogoutEventArgs e); - - public delegate void SocketConnectEventHandler(SocketConnectEventArgs e); - - public delegate void ConnectedEventHandler(ConnectedEventArgs e); - - public delegate void DisconnectedEventHandler(DisconnectedEventArgs e); - - public delegate void RenameRequestEventHandler(RenameRequestEventArgs e); - - public delegate void PlayerDeathEventHandler(PlayerDeathEventArgs e); - - public delegate void VirtueGumpRequestEventHandler(VirtueGumpRequestEventArgs e); - - public delegate void VirtueItemRequestEventHandler(VirtueItemRequestEventArgs e); - - public delegate void VirtueMacroRequestEventHandler(VirtueMacroRequestEventArgs e); - - public delegate void ChatRequestEventHandler(ChatRequestEventArgs e); - - public delegate void AccountLoginEventHandler(AccountLoginEventArgs e); - - public delegate void PaperdollRequestEventHandler(PaperdollRequestEventArgs e); - - public delegate void ProfileRequestEventHandler(ProfileRequestEventArgs e); - - public delegate void ChangeProfileRequestEventHandler(ChangeProfileRequestEventArgs e); - - public delegate void AggressiveActionEventHandler(AggressiveActionEventArgs e); - - public delegate void GameLoginEventHandler(GameLoginEventArgs e); - - public delegate void DeleteRequestEventHandler(DeleteRequestEventArgs e); - - public delegate void WorldLoadEventHandler(); - - public delegate void WorldSaveEventHandler(WorldSaveEventArgs e); - - public delegate void SetAbilityEventHandler(SetAbilityEventArgs e); - - public delegate void FastWalkEventHandler(FastWalkEventArgs e); - - public delegate void ServerStartedEventHandler(); - - public delegate void CreateGuildHandler(CreateGuildEventArgs e); - - public delegate void GuildGumpRequestHandler(GuildGumpRequestArgs e); - - public delegate void QuestGumpRequestHandler(QuestGumpRequestArgs e); - - public delegate void ClientVersionReceivedHandler(ClientVersionReceivedArgs e); - - public class ClientVersionReceivedArgs : EventArgs - { - public ClientVersionReceivedArgs(NetState state, ClientVersion cv) - { - State = state; - Version = cv; - } - - public NetState State{ get; } - - public ClientVersion Version{ get; } - } - - public class CreateGuildEventArgs : EventArgs - { - public CreateGuildEventArgs(uint id) => Id = id; - - public uint Id{ get; set; } - - public BaseGuild Guild{ get; set; } - } - - public class GuildGumpRequestArgs : EventArgs - { - public GuildGumpRequestArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class QuestGumpRequestArgs : EventArgs - { - public QuestGumpRequestArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class SetAbilityEventArgs : EventArgs - { - public SetAbilityEventArgs(Mobile mobile, int index) - { - Mobile = mobile; - Index = index; - } - - public Mobile Mobile{ get; } - - public int Index{ get; } - } - - public class DeleteRequestEventArgs : EventArgs - { - public DeleteRequestEventArgs(NetState state, int index) - { - State = state; - Index = index; - } - - public NetState State{ get; } - - public int Index{ get; } - } - - public class GameLoginEventArgs : EventArgs - { - public GameLoginEventArgs(NetState state, string un, string pw) - { - State = state; - Username = un; - Password = pw; - } - - public NetState State{ get; } - - public string Username{ get; } - - public string Password{ get; } - - public bool Accepted{ get; set; } - - public CityInfo[] CityInfo{ get; set; } - } - - public class AggressiveActionEventArgs : EventArgs - { - private static readonly Queue m_Pool = new Queue(); - - private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal) - { - Aggressed = aggressed; - Aggressor = aggressor; - Criminal = criminal; - } - - public Mobile Aggressed{ get; private set; } - - public Mobile Aggressor{ get; private set; } - - public bool Criminal{ get; private set; } - - public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal) - { - AggressiveActionEventArgs args; - - if (m_Pool.Count > 0) - { - args = m_Pool.Dequeue(); - - args.Aggressed = aggressed; - args.Aggressor = aggressor; - args.Criminal = criminal; - } - else - { - args = new AggressiveActionEventArgs(aggressed, aggressor, criminal); - } - - return args; - } - - public void Free() - { - m_Pool.Enqueue(this); - } - } - - public class ProfileRequestEventArgs : EventArgs - { - public ProfileRequestEventArgs(Mobile beholder, Mobile beheld) - { - Beholder = beholder; - Beheld = beheld; - } - - public Mobile Beholder{ get; } - - public Mobile Beheld{ get; } - } - - public class ChangeProfileRequestEventArgs : EventArgs - { - public ChangeProfileRequestEventArgs(Mobile beholder, Mobile beheld, string text) - { - Beholder = beholder; - Beheld = beheld; - Text = text; - } - - public Mobile Beholder{ get; } - - public Mobile Beheld{ get; } - - public string Text{ get; } - } - - public class PaperdollRequestEventArgs : EventArgs - { - public PaperdollRequestEventArgs(Mobile beholder, Mobile beheld) - { - Beholder = beholder; - Beheld = beheld; - } - - public Mobile Beholder{ get; } - - public Mobile Beheld{ get; } - } - - public class AccountLoginEventArgs : EventArgs - { - public AccountLoginEventArgs(NetState state, string username, string password) - { - State = state; - Username = username; - Password = password; - } - - public NetState State{ get; } - - public string Username{ get; } - - public string Password{ get; } - - public bool Accepted{ get; set; } - - public ALRReason RejectReason{ get; set; } - } - - public class VirtueItemRequestEventArgs : EventArgs - { - public VirtueItemRequestEventArgs(Mobile beholder, Mobile beheld, int gumpID) - { - Beholder = beholder; - Beheld = beheld; - GumpID = gumpID; - } - - public Mobile Beholder{ get; } - - public Mobile Beheld{ get; } - - public int GumpID{ get; } - } - - public class VirtueGumpRequestEventArgs : EventArgs - { - public VirtueGumpRequestEventArgs(Mobile beholder, Mobile beheld) - { - Beholder = beholder; - Beheld = beheld; - } - - public Mobile Beholder{ get; } - - public Mobile Beheld{ get; } - } - - public class VirtueMacroRequestEventArgs : EventArgs - { - public VirtueMacroRequestEventArgs(Mobile mobile, int virtueID) - { - Mobile = mobile; - VirtueID = virtueID; - } - - public Mobile Mobile{ get; } - - public int VirtueID{ get; } - } - - public class ChatRequestEventArgs : EventArgs - { - public ChatRequestEventArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class PlayerDeathEventArgs : EventArgs - { - public PlayerDeathEventArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class RenameRequestEventArgs : EventArgs - { - public RenameRequestEventArgs(Mobile from, Mobile target, string name) - { - From = from; - Target = target; - Name = name; - } - - public Mobile From{ get; } - - public Mobile Target{ get; } - - public string Name{ get; } - } - - public class LogoutEventArgs : EventArgs - { - public LogoutEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class SocketConnectEventArgs : EventArgs - { - public SocketConnectEventArgs(ConnectionContext c) - { - Context = c; - AllowConnection = true; - } - - public ConnectionContext Context{ get; } - - public bool AllowConnection{ get; set; } - } - - public class ConnectedEventArgs : EventArgs - { - public ConnectedEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class DisconnectedEventArgs : EventArgs - { - public DisconnectedEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class AnimateRequestEventArgs : EventArgs - { - public AnimateRequestEventArgs(Mobile m, string action) - { - Mobile = m; - Action = action; - } - - public Mobile Mobile{ get; } - - public string Action{ get; } - } - - public class CastSpellRequestEventArgs : EventArgs - { - public CastSpellRequestEventArgs(Mobile m, int spellID, Item book) - { - Mobile = m; - Spellbook = book; - SpellID = spellID; - } - - public Mobile Mobile{ get; } - - public Item Spellbook{ get; } - - public int SpellID{ get; } - } - - public class BandageTargetRequestEventArgs : EventArgs - { - public BandageTargetRequestEventArgs(Mobile m, Item bandage, Mobile target) - { - Mobile = m; - Bandage = bandage; - Target = target; - } - - public Mobile Mobile{ get; } - - public Item Bandage{ get; } - - public Mobile Target{ get; } - } - - public class OpenSpellbookRequestEventArgs : EventArgs - { - public OpenSpellbookRequestEventArgs(Mobile m, int type) - { - Mobile = m; - Type = type; - } - - public Mobile Mobile{ get; } - - public int Type{ get; } - } - - public class StunRequestEventArgs : EventArgs - { - public StunRequestEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class DisarmRequestEventArgs : EventArgs - { - public DisarmRequestEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class HelpRequestEventArgs : EventArgs - { - public HelpRequestEventArgs(Mobile m) => Mobile = m; - - public Mobile Mobile{ get; } - } - - public class ShutdownEventArgs : EventArgs - { - } - - public class CrashedEventArgs : EventArgs - { - public CrashedEventArgs(Exception e) => Exception = e; - - public Exception Exception{ get; } - - public bool Close{ get; set; } - } - - public class HungerChangedEventArgs : EventArgs - { - public HungerChangedEventArgs(Mobile mobile, int oldValue) - { - Mobile = mobile; - OldValue = oldValue; - } - - public Mobile Mobile{ get; } - - public int OldValue{ get; } - } - - public class MovementEventArgs : EventArgs - { - private static readonly Queue m_Pool = new Queue(); - - public MovementEventArgs(Mobile mobile, Direction dir) - { - Mobile = mobile; - Direction = dir; - } - - public Mobile Mobile{ get; private set; } - - public Direction Direction{ get; private set; } - - public bool Blocked{ get; set; } - - public static MovementEventArgs Create(Mobile mobile, Direction dir) - { - MovementEventArgs args; - - if (m_Pool.Count > 0) - { - args = m_Pool.Dequeue(); - - args.Mobile = mobile; - args.Direction = dir; - args.Blocked = false; - } - else - { - args = new MovementEventArgs(mobile, dir); - } - - return args; - } - - public void Free() - { - m_Pool.Enqueue(this); - } - } - - public class ServerListEventArgs : EventArgs - { - public ServerListEventArgs(NetState state, IAccount account) - { - State = state; - Account = account; - Servers = new List(); - } - - public NetState State{ get; } - - public IAccount Account{ get; } - - public bool Rejected{ get; set; } - - public List Servers{ get; } - - public void AddServer(string name, IPEndPoint address) - { - AddServer(name, 0, TimeZoneInfo.Local, address); - } - - public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) - { - Servers.Add(new ServerInfo(name, fullPercent, tz, address)); - } - } - - public struct SkillNameValue - { - public SkillName Name{ get; } - - public int Value{ get; } - - public SkillNameValue(SkillName name, int value) - { - Name = name; - Value = value; - } - } - - public class CharacterCreatedEventArgs : EventArgs - { - public CharacterCreatedEventArgs(NetState state, IAccount a, string name, bool female, int hue, int str, int dex, - int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, - int beardID, int beardHue, int profession, Race race) - { - State = state; - Account = a; - Name = name; - Female = female; - Hue = hue; - Str = str; - Dex = dex; - Int = intel; - City = city; - Skills = skills; - ShirtHue = shirtHue; - PantsHue = pantsHue; - HairID = hairID; - HairHue = hairHue; - BeardID = beardID; - BeardHue = beardHue; - Profession = profession; - Race = race; - } - - public NetState State{ get; } - - public IAccount Account{ get; } - - public Mobile Mobile{ get; set; } - - public string Name{ get; } - - public bool Female{ get; } - - public int Hue{ get; } - - public int Str{ get; } - - public int Dex{ get; } - - public int Int{ get; } - - public CityInfo City{ get; } - - public SkillNameValue[] Skills{ get; } - - public int ShirtHue{ get; } - - public int PantsHue{ get; } - - public int HairID{ get; } - - public int HairHue{ get; } - - public int BeardID{ get; } - - public int BeardHue{ get; } - - public int Profession{ get; set; } - - public Race Race{ get; } - } - - public class OpenDoorMacroEventArgs : EventArgs - { - public OpenDoorMacroEventArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class SpeechEventArgs : EventArgs - { - public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords) - { - Mobile = mobile; - Speech = speech; - Type = type; - Hue = hue; - Keywords = keywords; - } - - public Mobile Mobile{ get; } - - public string Speech{ get; set; } - - public MessageType Type{ get; } - - public int Hue{ get; } - - public int[] Keywords{ get; } - - public bool Handled{ get; set; } - - public bool Blocked{ get; set; } - - public bool HasKeyword(int keyword) - { - for (int i = 0; i < Keywords.Length; ++i) - if (Keywords[i] == keyword) - return true; - - return false; - } - } - - public class LoginEventArgs : EventArgs - { - public LoginEventArgs(Mobile mobile) => Mobile = mobile; - - public Mobile Mobile{ get; } - } - - public class WorldSaveEventArgs : EventArgs - { - public WorldSaveEventArgs(bool msg) => Message = msg; - - public bool Message{ get; } - } - - public class FastWalkEventArgs : EventArgs - { - public FastWalkEventArgs(NetState state) - { - NetState = state; - Blocked = false; - } - - public NetState NetState{ get; } - - public bool Blocked{ get; set; } - } - - public static class EventSink - { - public static event CharacterCreatedEventHandler CharacterCreated; - public static event OpenDoorMacroEventHandler OpenDoorMacroUsed; - public static event SpeechEventHandler Speech; - public static event LoginEventHandler Login; - public static event ServerListEventHandler ServerList; - public static event MovementEventHandler Movement; - public static event HungerChangedEventHandler HungerChanged; - public static event CrashedEventHandler Crashed; - public static event ShutdownEventHandler Shutdown; - public static event HelpRequestEventHandler HelpRequest; - public static event DisarmRequestEventHandler DisarmRequest; - public static event StunRequestEventHandler StunRequest; - public static event OpenSpellbookRequestEventHandler OpenSpellbookRequest; - public static event CastSpellRequestEventHandler CastSpellRequest; - public static event BandageTargetRequestEventHandler BandageTargetRequest; - public static event AnimateRequestEventHandler AnimateRequest; - public static event LogoutEventHandler Logout; - public static event SocketConnectEventHandler SocketConnect; - public static event ConnectedEventHandler Connected; - public static event DisconnectedEventHandler Disconnected; - public static event RenameRequestEventHandler RenameRequest; - public static event PlayerDeathEventHandler PlayerDeath; - public static event VirtueGumpRequestEventHandler VirtueGumpRequest; - public static event VirtueItemRequestEventHandler VirtueItemRequest; - public static event VirtueMacroRequestEventHandler VirtueMacroRequest; - public static event ChatRequestEventHandler ChatRequest; - public static event AccountLoginEventHandler AccountLogin; - public static event PaperdollRequestEventHandler PaperdollRequest; - public static event ProfileRequestEventHandler ProfileRequest; - public static event ChangeProfileRequestEventHandler ChangeProfileRequest; - public static event AggressiveActionEventHandler AggressiveAction; - public static event CommandEventHandler Command; - public static event GameLoginEventHandler GameLogin; - public static event DeleteRequestEventHandler DeleteRequest; - public static event WorldLoadEventHandler WorldLoad; - public static event WorldSaveEventHandler WorldSave; - public static event SetAbilityEventHandler SetAbility; - public static event FastWalkEventHandler FastWalk; - public static event CreateGuildHandler CreateGuild; - public static event ServerStartedEventHandler ServerStarted; - public static event GuildGumpRequestHandler GuildGumpRequest; - public static event QuestGumpRequestHandler QuestGumpRequest; - public static event ClientVersionReceivedHandler ClientVersionReceived; - - /* The following is a .NET 2.0 "Generic EventHandler" implementation. - * It is a breaking change; we would have to refactor all event handlers. - * This style does not appear to be in widespread use. - * We could also look into .NET 4.0 Action/Func implementations. - */ - - /* - public static event EventHandler CharacterCreated; - public static event EventHandler OpenDoorMacroUsed; - public static event EventHandler Speech; - public static event EventHandler Login; - public static event EventHandler ServerList; - public static event EventHandler Movement; - public static event EventHandler HungerChanged; - public static event EventHandler Crashed; - public static event EventHandler Shutdown; - public static event EventHandler HelpRequest; - public static event EventHandler DisarmRequest; - public static event EventHandler StunRequest; - public static event EventHandler OpenSpellbookRequest; - public static event EventHandler CastSpellRequest; - public static event EventHandler BandageTargetRequest; - public static event EventHandler AnimateRequest; - public static event EventHandler Logout; - public static event EventHandler SocketConnect; - public static event EventHandler Connected; - public static event EventHandler Disconnected; - public static event EventHandler RenameRequest; - public static event EventHandler PlayerDeath; - public static event EventHandler VirtueGumpRequest; - public static event EventHandler VirtueItemRequest; - public static event EventHandler VirtueMacroRequest; - public static event EventHandler ChatRequest; - public static event EventHandler AccountLogin; - public static event EventHandler PaperdollRequest; - public static event EventHandler ProfileRequest; - public static event EventHandler ChangeProfileRequest; - public static event EventHandler AggressiveAction; - public static event EventHandler Command; - public static event EventHandler GameLogin; - public static event EventHandler DeleteRequest; - public static event EventHandler WorldLoad; - public static event EventHandler WorldSave; - public static event EventHandler SetAbility; - public static event EventHandler FastWalk; - public static event EventHandler CreateGuild; - public static event EventHandler ServerStarted; - public static event EventHandler GuildGumpRequest; - public static event EventHandler QuestGumpRequest; - public static event EventHandler ClientVersionReceived; - */ - - public static void InvokeClientVersionReceived(ClientVersionReceivedArgs e) - { - ClientVersionReceived?.Invoke(e); - } - - public static void InvokeServerStarted() - { - ServerStarted?.Invoke(); - } - - public static void InvokeCreateGuild(CreateGuildEventArgs e) - { - CreateGuild?.Invoke(e); - } - - public static void InvokeSetAbility(SetAbilityEventArgs e) - { - SetAbility?.Invoke(e); - } - - public static void InvokeGuildGumpRequest(GuildGumpRequestArgs e) - { - GuildGumpRequest?.Invoke(e); - } - - public static void InvokeQuestGumpRequest(QuestGumpRequestArgs e) - { - QuestGumpRequest?.Invoke(e); - } - - public static void InvokeFastWalk(FastWalkEventArgs e) - { - FastWalk?.Invoke(e); - } - - public static void InvokeDeleteRequest(DeleteRequestEventArgs e) - { - DeleteRequest?.Invoke(e); - } - - public static void InvokeGameLogin(GameLoginEventArgs e) - { - GameLogin?.Invoke(e); - } - - public static void InvokeCommand(CommandEventArgs e) - { - Command?.Invoke(e); - } - - public static void InvokeAggressiveAction(AggressiveActionEventArgs e) - { - AggressiveAction?.Invoke(e); - } - - public static void InvokeProfileRequest(ProfileRequestEventArgs e) - { - ProfileRequest?.Invoke(e); - } - - public static void InvokeChangeProfileRequest(ChangeProfileRequestEventArgs e) - { - ChangeProfileRequest?.Invoke(e); - } - - public static void InvokePaperdollRequest(PaperdollRequestEventArgs e) - { - PaperdollRequest?.Invoke(e); - } - - public static void InvokeAccountLogin(AccountLoginEventArgs e) - { - AccountLogin?.Invoke(e); - } - - public static void InvokeChatRequest(ChatRequestEventArgs e) - { - ChatRequest?.Invoke(e); - } - - public static void InvokeVirtueItemRequest(VirtueItemRequestEventArgs e) - { - VirtueItemRequest?.Invoke(e); - } - - public static void InvokeVirtueGumpRequest(VirtueGumpRequestEventArgs e) - { - VirtueGumpRequest?.Invoke(e); - } - - public static void InvokeVirtueMacroRequest(VirtueMacroRequestEventArgs e) - { - VirtueMacroRequest?.Invoke(e); - } - - public static void InvokePlayerDeath(PlayerDeathEventArgs e) - { - PlayerDeath?.Invoke(e); - } - - public static void InvokeRenameRequest(RenameRequestEventArgs e) - { - RenameRequest?.Invoke(e); - } - - public static void InvokeLogout(LogoutEventArgs e) - { - Logout?.Invoke(e); - } - - public static void InvokeSocketConnect(SocketConnectEventArgs e) - { - SocketConnect?.Invoke(e); - } - - public static void InvokeConnected(ConnectedEventArgs e) - { - Connected?.Invoke(e); - } - - public static void InvokeDisconnected(DisconnectedEventArgs e) - { - Disconnected?.Invoke(e); - } - - public static void InvokeAnimateRequest(AnimateRequestEventArgs e) - { - AnimateRequest?.Invoke(e); - } - - public static void InvokeCastSpellRequest(CastSpellRequestEventArgs e) - { - CastSpellRequest?.Invoke(e); - } - - public static void InvokeBandageTargetRequest(BandageTargetRequestEventArgs e) - { - BandageTargetRequest?.Invoke(e); - } - - public static void InvokeOpenSpellbookRequest(OpenSpellbookRequestEventArgs e) - { - OpenSpellbookRequest?.Invoke(e); - } - - public static void InvokeDisarmRequest(DisarmRequestEventArgs e) - { - DisarmRequest?.Invoke(e); - } - - public static void InvokeStunRequest(StunRequestEventArgs e) - { - StunRequest?.Invoke(e); - } - - public static void InvokeHelpRequest(HelpRequestEventArgs e) - { - HelpRequest?.Invoke(e); - } - - public static void InvokeShutdown(ShutdownEventArgs e) - { - Shutdown?.Invoke(e); - } - - public static void InvokeCrashed(CrashedEventArgs e) - { - Crashed?.Invoke(e); - } - - public static void InvokeHungerChanged(HungerChangedEventArgs e) - { - HungerChanged?.Invoke(e); - } - - public static void InvokeMovement(MovementEventArgs e) - { - Movement?.Invoke(e); - } - - public static void InvokeServerList(ServerListEventArgs e) - { - ServerList?.Invoke(e); - } - - public static void InvokeLogin(LoginEventArgs e) - { - Login?.Invoke(e); - } - - public static void InvokeSpeech(SpeechEventArgs e) - { - Speech?.Invoke(e); - } - - public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) - { - CharacterCreated?.Invoke(e); - } - - public static void InvokeOpenDoorMacroUsed(OpenDoorMacroEventArgs e) - { - OpenDoorMacroUsed?.Invoke(e); - } - - public static void InvokeWorldLoad() - { - WorldLoad?.Invoke(); - } - - public static void InvokeWorldSave(WorldSaveEventArgs e) - { - WorldSave?.Invoke(e); - } - - public static void Reset() - { - CharacterCreated = null; - OpenDoorMacroUsed = null; - Speech = null; - Login = null; - ServerList = null; - Movement = null; - HungerChanged = null; - Crashed = null; - Shutdown = null; - HelpRequest = null; - DisarmRequest = null; - StunRequest = null; - OpenSpellbookRequest = null; - CastSpellRequest = null; - BandageTargetRequest = null; - AnimateRequest = null; - Logout = null; - SocketConnect = null; - Connected = null; - Disconnected = null; - RenameRequest = null; - PlayerDeath = null; - VirtueGumpRequest = null; - VirtueItemRequest = null; - VirtueMacroRequest = null; - ChatRequest = null; - AccountLogin = null; - PaperdollRequest = null; - ProfileRequest = null; - ChangeProfileRequest = null; - AggressiveAction = null; - Command = null; - GameLogin = null; - DeleteRequest = null; - WorldLoad = null; - WorldSave = null; - SetAbility = null; - GuildGumpRequest = null; - QuestGumpRequest = null; - } - } -} diff --git a/Projects/Server/Events/AccountLoginEvent.cs b/Projects/Server/Events/AccountLoginEvent.cs new file mode 100644 index 000000000..7fc1df036 --- /dev/null +++ b/Projects/Server/Events/AccountLoginEvent.cs @@ -0,0 +1,52 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: AccountLoginEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Network; + +namespace Server +{ + public class AccountLoginEventArgs : EventArgs + { + public AccountLoginEventArgs(NetState state, string username, string password) + { + State = state; + Username = username; + Password = password; + } + + public NetState State{ get; } + + public string Username{ get; } + + public string Password{ get; } + + public bool Accepted{ get; set; } + + public ALRReason RejectReason{ get; set; } + } + + public static partial class EventSink + { + public static event Action AccountLogin; + public static void InvokeAccountLogin(AccountLoginEventArgs e) => AccountLogin?.Invoke(e); + } +} diff --git a/Projects/Server/Events/AggressiveActionEvent.cs b/Projects/Server/Events/AggressiveActionEvent.cs new file mode 100644 index 000000000..c4f4ae29e --- /dev/null +++ b/Projects/Server/Events/AggressiveActionEvent.cs @@ -0,0 +1,75 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: AggressiveActionEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Server +{ + public class AggressiveActionEventArgs : EventArgs + { + private static Queue m_Pool = new Queue(); + + private AggressiveActionEventArgs(Mobile aggressed, Mobile aggressor, bool criminal) + { + Aggressed = aggressed; + Aggressor = aggressor; + Criminal = criminal; + } + + public Mobile Aggressed{ get; private set; } + + public Mobile Aggressor{ get; private set; } + + public bool Criminal{ get; private set; } + + public static AggressiveActionEventArgs Create(Mobile aggressed, Mobile aggressor, bool criminal) + { + AggressiveActionEventArgs args; + + if (m_Pool.Count > 0) + { + args = m_Pool.Dequeue(); + + args.Aggressed = aggressed; + args.Aggressor = aggressor; + args.Criminal = criminal; + } + else + { + args = new AggressiveActionEventArgs(aggressed, aggressor, criminal); + } + + return args; + } + + public void Free() + { + m_Pool.Enqueue(this); + } + } + + public static partial class EventSink + { + public static event Action AggressiveAction; + public static void InvokeAggressiveAction(AggressiveActionEventArgs e) => AggressiveAction?.Invoke(e); + } +} diff --git a/Projects/Server/Events/CharacterCreatedEvent.cs b/Projects/Server/Events/CharacterCreatedEvent.cs new file mode 100644 index 000000000..0ed478396 --- /dev/null +++ b/Projects/Server/Events/CharacterCreatedEvent.cs @@ -0,0 +1,110 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: CharacterCreatedEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Accounting; +using Server.Network; + +namespace Server +{ + public class CharacterCreatedEventArgs : EventArgs + { + public CharacterCreatedEventArgs(NetState state, IAccount a, string name, bool female, int hue, int str, int dex, + int intel, CityInfo city, SkillNameValue[] skills, int shirtHue, int pantsHue, int hairID, int hairHue, + int beardID, int beardHue, int profession, Race race) + { + State = state; + Account = a; + Name = name; + Female = female; + Hue = hue; + Str = str; + Dex = dex; + Int = intel; + City = city; + Skills = skills; + ShirtHue = shirtHue; + PantsHue = pantsHue; + HairID = hairID; + HairHue = hairHue; + BeardID = beardID; + BeardHue = beardHue; + Profession = profession; + Race = race; + } + + public NetState State{ get; } + + public IAccount Account{ get; } + + public Mobile Mobile{ get; set; } + + public string Name{ get; } + + public bool Female{ get; } + + public int Hue{ get; } + + public int Str{ get; } + + public int Dex{ get; } + + public int Int{ get; } + + public CityInfo City{ get; } + + public SkillNameValue[] Skills{ get; } + + public int ShirtHue{ get; } + + public int PantsHue{ get; } + + public int HairID{ get; } + + public int HairHue{ get; } + + public int BeardID{ get; } + + public int BeardHue{ get; } + + public int Profession{ get; set; } + + public Race Race{ get; } + } + + public struct SkillNameValue + { + public SkillName Name{ get; } + + public int Value{ get; } + + public SkillNameValue(SkillName name, int value) + { + Name = name; + Value = value; + } + } + + public static partial class EventSink { + public static event Action CharacterCreated; + public static void InvokeCharacterCreated(CharacterCreatedEventArgs e) => CharacterCreated?.Invoke(e); + } +} diff --git a/Projects/Server/Events/CreateGuildEvent.cs b/Projects/Server/Events/CreateGuildEvent.cs new file mode 100644 index 000000000..4020b92f0 --- /dev/null +++ b/Projects/Server/Events/CreateGuildEvent.cs @@ -0,0 +1,41 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: CreateGuildEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Guilds; + +namespace Server +{ + public class CreateGuildEventArgs : EventArgs + { + public CreateGuildEventArgs(uint id) => Id = id; + + public uint Id{ get; set; } + + public BaseGuild Guild{ get; set; } + } + + public static partial class EventSink + { + public static event Action CreateGuild; + public static void InvokeCreateGuild(CreateGuildEventArgs e) => CreateGuild?.Invoke(e); + } +} diff --git a/Projects/Server/Events/EventSink.cs b/Projects/Server/Events/EventSink.cs new file mode 100644 index 000000000..3a3ceb79e --- /dev/null +++ b/Projects/Server/Events/EventSink.cs @@ -0,0 +1,150 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: EventSink.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Collections.Generic; +using Server.Network; + +namespace Server +{ + public static partial class EventSink + { + public static event Action OpenDoorMacroUsed; + public static void InvokeOpenDoorMacroUsed(Mobile m) => OpenDoorMacroUsed?.Invoke(m); + + public static event Action Login; + public static void InvokeLogin(Mobile m) => Login?.Invoke(m); + + public static event Action HungerChanged; + public static void InvokeHungerChanged(Mobile mobile, int oldValue) => HungerChanged?.Invoke(mobile, oldValue); + + public static event Action Shutdown; + public static void InvokeShutdown() => Shutdown?.Invoke(); + + public static event Action HelpRequest; + public static void InvokeHelpRequest(Mobile m) => HelpRequest?.Invoke(m); + + public static event Action DisarmRequest; + public static void InvokeDisarmRequest(Mobile m) => DisarmRequest?.Invoke(m); + + public static event Action StunRequest; + public static void InvokeStunRequest(Mobile m) => StunRequest?.Invoke(m); + + public static event Action OpenSpellbookRequest; + public static void InvokeOpenSpellbookRequest(Mobile m, int type) => OpenSpellbookRequest?.Invoke(m, type); + + public static event Action CastSpellRequest; + public static void InvokeCastSpellRequest(Mobile m, int spellID, Item book) => CastSpellRequest?.Invoke(m, spellID, book); + + public static event Action BandageTargetRequest; + public static void InvokeBandageTargetRequest(Mobile m, Item bandage, Mobile target) => BandageTargetRequest?.Invoke(m, bandage, target); + + public static event Action AnimateRequest; + public static void InvokeAnimateRequest(Mobile m, string action) => AnimateRequest?.Invoke(m, action); + + public static event Action Logout; + public static void InvokeLogout(Mobile m) => Logout?.Invoke(m); + + public static event Action Connected; + public static void InvokeConnected(Mobile m) => Connected?.Invoke(m); + + public static event Action Disconnected; + public static void InvokeDisconnected(Mobile m) => Disconnected?.Invoke(m); + + public static event Action RenameRequest; + public static void InvokeRenameRequest(Mobile from, Mobile target, string name) => RenameRequest?.Invoke(from, target, name); + + public static event Action PlayerDeath; + public static void InvokePlayerDeath(Mobile m) => PlayerDeath?.Invoke(m); + + public static event Action VirtueGumpRequest; + public static void InvokeVirtueGumpRequest(Mobile beholder, Mobile beheld) => VirtueGumpRequest?.Invoke(beholder, beheld); + + public static event Action VirtueItemRequest; + public static void InvokeVirtueItemRequest(Mobile beholder, Mobile beheld, int gumpID) => VirtueItemRequest?.Invoke(beholder, beheld, gumpID); + + public static event Action VirtueMacroRequest; + public static void InvokeVirtueMacroRequest(Mobile mobile, int virtueID) => VirtueMacroRequest?.Invoke(mobile, virtueID); + + public static event Action ChatRequest; + public static void InvokeChatRequest(Mobile m) => ChatRequest?.Invoke(m); + + + public static event Action PaperdollRequest; + public static void InvokePaperdollRequest(Mobile beholder, Mobile beheld) => PaperdollRequest?.Invoke(beholder ,beheld); + + public static event Action ProfileRequest; + public static void InvokeProfileRequest(Mobile beholder, Mobile beheld) => ProfileRequest?.Invoke(beholder, beheld); + + public static event Action ChangeProfileRequest; + public static void InvokeChangeProfileRequest(Mobile beholder, Mobile beheld, string text) => + ChangeProfileRequest?.Invoke(beholder, beheld, text); + + + public static event Action DeleteRequest; + public static void InvokeDeleteRequest(NetState state, int index) => DeleteRequest?.Invoke(state, index); + + public static event Action WorldLoad; + public static void InvokeWorldLoad() => WorldLoad?.Invoke(); + + public static event Action WorldSave; + public static void InvokeWorldSave(bool sendMessage) => WorldSave?.Invoke(sendMessage); + + public static event Action SetAbility; + public static void InvokeSetAbility(Mobile mobile, int index) => SetAbility?.Invoke(mobile, index); + + public static event Action ServerStarted; + public static void InvokeServerStarted() => ServerStarted?.Invoke(); + + public static event Action GuildGumpRequest; + public static void InvokeGuildGumpRequest(Mobile m) => GuildGumpRequest?.Invoke(m); + + public static event Action QuestGumpRequest; + public static void InvokeQuestGumpRequest(Mobile m) => QuestGumpRequest?.Invoke(m); + + public static event Action ClientVersionReceived; + public static void InvokeClientVersionReceived(NetState state, ClientVersion cv) => ClientVersionReceived?.Invoke(state, cv); + + public static event Action> EquipMacro; + public static void InvokeEquipMacro(Mobile m, List list) + { + if (list?.Count > 0) + EquipMacro?.Invoke(m, list); + } + + public static event Action> UnequipMacro; + + public static void InvokeUnequipMacro(Mobile m, List layers) + { + if (layers?.Count > 0) + UnequipMacro?.Invoke(m, layers); + } + + public static event Action TargetedSpell; + public static void InvokeTargetedSpell(Mobile m, IEntity target, int spellId) => TargetedSpell?.Invoke(m, target, spellId); + + public static event Action TargetedSkillUse; + public static void InvokeTargetedSkillUse(Mobile m, IEntity target, int skillId) => TargetedSkillUse?.Invoke(m, target, skillId); + + public static event Action TargetByResourceMacro; + public static void InvokeTargetByResourceMacro(Mobile m, Item item, short resourceType) => TargetByResourceMacro?.Invoke(m, item, resourceType); + } +} diff --git a/Projects/Server/Events/FastwalkEvent.cs b/Projects/Server/Events/FastwalkEvent.cs new file mode 100644 index 000000000..a40757d16 --- /dev/null +++ b/Projects/Server/Events/FastwalkEvent.cs @@ -0,0 +1,45 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: FastWalkEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Network; + +namespace Server +{ + public class FastWalkEventArgs : EventArgs + { + public FastWalkEventArgs(NetState state) + { + NetState = state; + Blocked = false; + } + + public NetState NetState{ get; } + + public bool Blocked{ get; set; } + } + + public static partial class EventSink + { + public static event Action FastWalk; + public static void InvokeFastWalk(FastWalkEventArgs e) => FastWalk?.Invoke(e); + } +} diff --git a/Projects/Server/Events/GameLoginEvent.cs b/Projects/Server/Events/GameLoginEvent.cs new file mode 100644 index 000000000..054a5db4b --- /dev/null +++ b/Projects/Server/Events/GameLoginEvent.cs @@ -0,0 +1,52 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: GameLoginEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Server.Network; + +namespace Server +{ + public class GameLoginEventArgs : EventArgs + { + public GameLoginEventArgs(NetState state, string un, string pw) + { + State = state; + Username = un; + Password = pw; + } + + public NetState State{ get; } + + public string Username{ get; } + + public string Password{ get; } + + public bool Accepted{ get; set; } + + public CityInfo[] CityInfo{ get; set; } + } + + public static partial class EventSink + { + public static event Action GameLogin; + public static void InvokeGameLogin(GameLoginEventArgs e) => GameLogin?.Invoke(e); + } +} diff --git a/Projects/Server/Events/MovementEvent.cs b/Projects/Server/Events/MovementEvent.cs new file mode 100644 index 000000000..6e63d6d4c --- /dev/null +++ b/Projects/Server/Events/MovementEvent.cs @@ -0,0 +1,74 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: MovementEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Collections.Generic; + +namespace Server +{ + public class MovementEventArgs : EventArgs + { + private static Queue m_Pool = new Queue(); + + public MovementEventArgs(Mobile mobile, Direction dir) + { + Mobile = mobile; + Direction = dir; + } + + public Mobile Mobile{ get; private set; } + + public Direction Direction{ get; private set; } + + public bool Blocked{ get; set; } + + public static MovementEventArgs Create(Mobile mobile, Direction dir) + { + MovementEventArgs args; + + if (m_Pool.Count > 0) + { + args = m_Pool.Dequeue(); + + args.Mobile = mobile; + args.Direction = dir; + args.Blocked = false; + } + else + { + args = new MovementEventArgs(mobile, dir); + } + + return args; + } + + public void Free() + { + m_Pool.Enqueue(this); + } + } + + public static partial class EventSink + { + public static event Action Movement; + public static void InvokeMovement(MovementEventArgs e) => Movement?.Invoke(e); + } +} diff --git a/Projects/Server/Events/ServerCrashedEvent.cs b/Projects/Server/Events/ServerCrashedEvent.cs new file mode 100644 index 000000000..0bda10110 --- /dev/null +++ b/Projects/Server/Events/ServerCrashedEvent.cs @@ -0,0 +1,40 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ServerCrashedEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; + +namespace Server +{ + public class ServerCrashedEventArgs : EventArgs + { + public ServerCrashedEventArgs(Exception e) => Exception = e; + + public Exception Exception{ get; } + + public bool Close{ get; set; } + } + + public static partial class EventSink + { + public static event Action ServerCrashed; + public static void InvokeServerCrashed(ServerCrashedEventArgs e) => ServerCrashed?.Invoke(e); + } +} diff --git a/Projects/Server/Events/ServerListEvent.cs b/Projects/Server/Events/ServerListEvent.cs new file mode 100644 index 000000000..b403933cf --- /dev/null +++ b/Projects/Server/Events/ServerListEvent.cs @@ -0,0 +1,63 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ServerListEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using System.Collections.Generic; +using System.Net; +using Server.Accounting; +using Server.Network; + +namespace Server +{ + public class ServerListEventArgs : EventArgs + { + public ServerListEventArgs(NetState state, IAccount account) + { + State = state; + Account = account; + Servers = new List(); + } + + public NetState State{ get; } + + public IAccount Account{ get; } + + public bool Rejected{ get; set; } + + public List Servers{ get; } + + public void AddServer(string name, IPEndPoint address) + { + AddServer(name, 0, TimeZoneInfo.Local, address); + } + + public void AddServer(string name, int fullPercent, TimeZoneInfo tz, IPEndPoint address) + { + Servers.Add(new ServerInfo(name, fullPercent, tz, address)); + } + } + + public static partial class EventSink + { + public static event Action ServerList; + public static void InvokeServerList(ServerListEventArgs e) => ServerList?.Invoke(e); + } +} diff --git a/Projects/Server/Events/SocketConnectionEvent.cs b/Projects/Server/Events/SocketConnectionEvent.cs new file mode 100644 index 000000000..bef6f8c72 --- /dev/null +++ b/Projects/Server/Events/SocketConnectionEvent.cs @@ -0,0 +1,45 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2020 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: SocketConnectionEvent.cs * + * Created: 2020/04/11 - Updated: 2020/04/11 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + +using System; +using Microsoft.AspNetCore.Connections; + +namespace Server +{ + public class SocketConnectEventArgs : EventArgs + { + public SocketConnectEventArgs(ConnectionContext c) + { + Context = c; + AllowConnection = true; + } + + public ConnectionContext Context{ get; } + + public bool AllowConnection{ get; set; } + } + + public static partial class EventSink + { + public static event Action SocketConnect; + public static void InvokeSocketConnect(SocketConnectEventArgs e) => SocketConnect?.Invoke(e); + } +} diff --git a/Projects/Server/Events/SpeechEvent.cs b/Projects/Server/Events/SpeechEvent.cs new file mode 100644 index 000000000..2f1a76086 --- /dev/null +++ b/Projects/Server/Events/SpeechEvent.cs @@ -0,0 +1,46 @@ +using System; +using Server.Network; + +namespace Server +{ + public class SpeechEventArgs : EventArgs + { + public SpeechEventArgs(Mobile mobile, string speech, MessageType type, int hue, int[] keywords) + { + Mobile = mobile; + Speech = speech; + Type = type; + Hue = hue; + Keywords = keywords; + } + + public Mobile Mobile{ get; } + + public string Speech{ get; set; } + + public MessageType Type{ get; } + + public int Hue{ get; } + + public int[] Keywords{ get; } + + public bool Handled{ get; set; } + + public bool Blocked{ get; set; } + + public bool HasKeyword(int keyword) + { + for (int i = 0; i < Keywords.Length; ++i) + if (Keywords[i] == keyword) + return true; + + return false; + } + } + + public static partial class EventSink + { + public static event Action Speech; + public static void InvokeSpeech(SpeechEventArgs e) => Speech?.Invoke(e); + } +} diff --git a/Projects/Server/Main.cs b/Projects/Server/Main.cs index c91fb518b..e9328c0ba 100644 --- a/Projects/Server/Main.cs +++ b/Projects/Server/Main.cs @@ -251,9 +251,9 @@ namespace Server try { - CrashedEventArgs args = new CrashedEventArgs(e.ExceptionObject as Exception); + ServerCrashedEventArgs args = new ServerCrashedEventArgs(e.ExceptionObject as Exception); - EventSink.InvokeCrashed(args); + EventSink.InvokeServerCrashed(args); close = args.Close; } @@ -318,7 +318,7 @@ namespace Server World.WaitForWriteCompletion(); if (!m_Crashed) - EventSink.InvokeShutdown(new ShutdownEventArgs()); + EventSink.InvokeShutdown(); Timer.TimerThread.Set(); diff --git a/Projects/Server/Mobile.cs b/Projects/Server/Mobile.cs index bc75d05fc..91d558f71 100644 --- a/Projects/Server/Mobile.cs +++ b/Projects/Server/Mobile.cs @@ -707,7 +707,7 @@ namespace Server { m_Hunger = value; - EventSink.InvokeHungerChanged(new HungerChangedEventArgs(this, oldValue)); + EventSink.InvokeHungerChanged(this, oldValue); } } } @@ -1461,7 +1461,7 @@ namespace Server if (m_NetState == null) { OnDisconnected(); - EventSink.InvokeDisconnected(new DisconnectedEventArgs(this)); + EventSink.InvokeDisconnected(this); // Disconnected, start the logout timer @@ -1476,7 +1476,7 @@ namespace Server else { OnConnected(); - EventSink.InvokeConnected(new ConnectedEventArgs(this)); + EventSink.InvokeConnected(this); // Connected, stop the logout timer and if needed, move to the world @@ -1818,16 +1818,7 @@ namespace Server public virtual bool KeepsItemsOnDeath => m_AccessLevel > AccessLevel.Player; - public bool HasTrade - { - get - { - if (m_NetState != null) - return m_NetState.Trades.Count > 0; - - return false; - } - } + public bool HasTrade => m_NetState?.Trades.Count > 0; public bool NoMoveHS{ get; set; } @@ -4394,7 +4385,7 @@ namespace Server Stam = 0; Mana = 0; - EventSink.InvokePlayerDeath(new PlayerDeathEventArgs(this)); + EventSink.InvokePlayerDeath(this); ProcessDeltaQueue(); @@ -6456,10 +6447,10 @@ namespace Server return false; return this == m || m.m_Map == m_Map && - (!m.Hidden || m_AccessLevel != AccessLevel.Player && - (m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) && - (m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive || - m_AccessLevel > AccessLevel.Player || m.Warmode); + (!m.Hidden || m_AccessLevel != AccessLevel.Player && + (m_AccessLevel >= m.AccessLevel || m_AccessLevel >= AccessLevel.Administrator)) && + (m.Alive || Core.SE && Skills.SpiritSpeak.Value >= 100.0 || !Alive || + m_AccessLevel > AccessLevel.Player || m.Warmode); } public virtual bool CanBeRenamedBy(Mobile from) => from.AccessLevel >= AccessLevel.GameMaster && from.m_AccessLevel > m_AccessLevel; @@ -7069,7 +7060,7 @@ namespace Server public virtual void DisplayPaperdollTo(Mobile to) { - EventSink.InvokePaperdollRequest(new PaperdollRequestEventArgs(to, this)); + EventSink.InvokePaperdollRequest(to, this); } /// @@ -7548,7 +7539,7 @@ namespace Server { if (m_Mobile.m_Map != Map.Internal) { - EventSink.InvokeLogout(new LogoutEventArgs(m_Mobile)); + EventSink.InvokeLogout(m_Mobile); m_Mobile.LogoutLocation = m_Mobile.m_Location; m_Mobile.LogoutMap = m_Mobile.m_Map; @@ -7725,8 +7716,8 @@ namespace Server m_Callback(from, ""); else m_CancelCallback?.Invoke(@from, ""); + } } - } public Prompt BeginPrompt(PromptCallback callback, PromptCallback cancelCallback) { diff --git a/Projects/Server/MultiData.cs b/Projects/Server/MultiData.cs index 7dffc4cbd..aa0ab0f0b 100644 --- a/Projects/Server/MultiData.cs +++ b/Projects/Server/MultiData.cs @@ -19,91 +19,203 @@ ***************************************************************************/ using System; +using System.Buffers; +using System.Collections.Generic; using System.IO; +using Server.Network; namespace Server { public static class MultiData { - private static readonly MultiComponentList[] m_Components; + public static Dictionary Components { get; } = new Dictionary(); - private static readonly FileStream m_Index; - private static readonly FileStream m_Stream; private static readonly BinaryReader m_IndexReader; private static readonly BinaryReader m_StreamReader; + private static readonly bool UsingUOPFormat; + static MultiData() { + string multiUOPPath = Core.FindDataFile("MultiCollection.uop"); + + if (File.Exists(multiUOPPath)) + { + LoadUOP(multiUOPPath); + UsingUOPFormat = true; + return; + } + string idxPath = Core.FindDataFile("multi.idx"); string mulPath = Core.FindDataFile("multi.mul"); if (File.Exists(idxPath) && File.Exists(mulPath)) { - m_Index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read); - m_IndexReader = new BinaryReader(m_Index); + var idx = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read); + m_IndexReader = new BinaryReader(idx); - m_Stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read); - m_StreamReader = new BinaryReader(m_Stream); - - m_Components = new MultiComponentList[(int)(m_Index.Length / 12)]; + var stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read); + m_StreamReader = new BinaryReader(stream); string vdPath = Core.FindDataFile("verdata.mul"); - if (File.Exists(vdPath)) + if (!File.Exists(vdPath)) return; + + using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read); + BinaryReader bin = new BinaryReader(fs); + + int count = bin.ReadInt32(); + + for (int i = 0; i < count; ++i) { - using FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read); - BinaryReader bin = new BinaryReader(fs); + int file = bin.ReadInt32(); + int index = bin.ReadInt32(); + int lookup = bin.ReadInt32(); + int length = bin.ReadInt32(); + bin.ReadInt32(); // extra - int count = bin.ReadInt32(); - - for (int i = 0; i < count; ++i) + if (file == 14 && index >= 0 && lookup >= 0 && length > 0) { - int file = bin.ReadInt32(); - int index = bin.ReadInt32(); - int lookup = bin.ReadInt32(); - int length = bin.ReadInt32(); - int extra = bin.ReadInt32(); + bin.BaseStream.Seek(lookup, SeekOrigin.Begin); - if (file == 14 && index >= 0 && index < m_Components.Length && lookup >= 0 && length > 0) - { - bin.BaseStream.Seek(lookup, SeekOrigin.Begin); + Components[index] = new MultiComponentList(bin, length / 12); - m_Components[index] = new MultiComponentList(bin, length / 12); - - bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin); - } + bin.BaseStream.Seek(24 + i * 20, SeekOrigin.Begin); } - - bin.Close(); } + + bin.Close(); } else - { Console.WriteLine("Warning: Multi data files not found"); - - m_Components = new MultiComponentList[0]; - } } public static MultiComponentList GetComponents(int multiID) { MultiComponentList mcl; - if (multiID >= 0 && multiID < m_Components.Length) - { - mcl = m_Components[multiID]; + multiID &= 0x3FFF; - if (mcl == null) - m_Components[multiID] = mcl = Load(multiID); - } + if (Components.ContainsKey(multiID)) + mcl = Components[multiID]; + else if (!UsingUOPFormat) + Components[multiID] = mcl = Load(multiID); else - { mcl = MultiComponentList.Empty; - } return mcl; } + public static void LoadUOP(string path) + { + var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read); + BinaryReader streamReader = new BinaryReader(stream); + + // Head Information Start + if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files + return; + + if (streamReader.ReadInt32() > 5) // Bad Version + return; + + // Multi ID List Array Start + UOPHash.BuildChunkIDs(out var chunkIds); + // Multi ID List Array End + + streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43 + long startAddress = streamReader.ReadInt64(); + + streamReader.ReadInt32(); + streamReader.ReadInt32(); + + stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End + + long nextBlock; + + do + { + int blockFileCount = streamReader.ReadInt32(); + nextBlock = streamReader.ReadInt64(); + + int index = 0; + + do + { + long offset = streamReader.ReadInt64(); + + int headerSize = streamReader.ReadInt32(); // header length + int compressedSize = streamReader.ReadInt32(); // compressed size + int decompressedSize = streamReader.ReadInt32(); // decompressed size + + ulong filehash = streamReader.ReadUInt64(); // filename hash (HashLittle2) + streamReader.ReadUInt32(); + short compressionMethod = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib) + + index++; + + if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin + continue; + + chunkIds.TryGetValue(filehash, out var chunkID); + + long position = stream.Position; // save current position + + stream.Seek(offset + headerSize, SeekOrigin.Begin); + + Span sourceData = new byte[compressedSize]; + + if (stream.Read(sourceData) != compressedSize) + continue; + + Span data; + + if (compressionMethod == 1) + { + data = new byte[decompressedSize]; + Compression.Unpack(data, ref decompressedSize, sourceData, compressedSize); + } + else + data = sourceData; + + var tileList = new List(); + + // Skip the first 4 bytes + BufferReader reader = new BufferReader(data); + + reader.Advance(4); // ??? + reader.TryReadLittleEndian(out uint count); + + for (uint i = 0; i < count; i++) + { + reader.TryReadLittleEndian(out ushort itemid); + reader.TryReadLittleEndian(out short x); + reader.TryReadLittleEndian(out short y); + reader.TryReadLittleEndian(out short z); + reader.TryReadLittleEndian(out ushort flagValue); + + TileFlag tileFlag = flagValue switch + { + 1 => TileFlag.None, + 257 => TileFlag.Generic, + _ => TileFlag.Background // 0 + }; + + reader.TryReadLittleEndian(out uint clilocsCount); + reader.Advance(clilocsCount * 4); // bypass binary block + + tileList.Add(new MultiTileEntry(itemid, x, y, z, tileFlag)); + } + + Components[chunkID] = new MultiComponentList(tileList); + + stream.Seek(position, SeekOrigin.Begin); // back to position + } + while (index < blockFileCount); + } + while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0); + } + + // TODO: Change this to read the file all during load time public static MultiComponentList Load(int multiID) { try @@ -131,9 +243,9 @@ namespace Server { public ushort m_ItemID; public short m_OffsetX, m_OffsetY, m_OffsetZ; - public int m_Flags; + public TileFlag m_Flags; - public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, int flags) + public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, TileFlag flags) { m_ItemID = itemID; m_OffsetX = xOffset; @@ -205,7 +317,7 @@ namespace Server allTiles[i].m_OffsetX = reader.ReadShort(); allTiles[i].m_OffsetY = reader.ReadShort(); allTiles[i].m_OffsetZ = reader.ReadShort(); - allTiles[i].m_Flags = reader.ReadInt(); + allTiles[i].m_Flags = (TileFlag)reader.ReadInt(); } else for (int i = 0; i < length; ++i) @@ -214,7 +326,7 @@ namespace Server allTiles[i].m_OffsetX = reader.ReadShort(); allTiles[i].m_OffsetY = reader.ReadShort(); allTiles[i].m_OffsetZ = reader.ReadShort(); - allTiles[i].m_Flags = reader.ReadInt(); + allTiles[i].m_Flags = (TileFlag)reader.ReadInt(); } TileList[][] tiles = new TileList[Width][]; @@ -253,10 +365,11 @@ namespace Server allTiles[i].m_OffsetX = reader.ReadInt16(); allTiles[i].m_OffsetY = reader.ReadInt16(); allTiles[i].m_OffsetZ = reader.ReadInt16(); - allTiles[i].m_Flags = reader.ReadInt32(); if (PostHSFormat) - reader.ReadInt32(); // ?? + allTiles[i].m_Flags = (TileFlag)reader.ReadUInt64(); + else + allTiles[i].m_Flags = (TileFlag)reader.ReadUInt32(); MultiTileEntry e = allTiles[i]; @@ -306,6 +419,63 @@ namespace Server Tiles[x][y] = tiles[x][y].ToArray(); } + public MultiComponentList(List list) + { + var allTiles = List = new MultiTileEntry[list.Count]; + + for (int i = 0; i < list.Count; ++i) + { + allTiles[i].m_ItemID = list[i].m_ItemID; + allTiles[i].m_OffsetX = list[i].m_OffsetX; + allTiles[i].m_OffsetY = list[i].m_OffsetY; + allTiles[i].m_OffsetZ = list[i].m_OffsetZ; + + allTiles[i].m_Flags = list[i].m_Flags; + + MultiTileEntry e = allTiles[i]; + + if (i == 0 || e.m_Flags != 0) + { + if (e.m_OffsetX < m_Min.m_X) m_Min.m_X = e.m_OffsetX; + + if (e.m_OffsetY < m_Min.m_Y) m_Min.m_Y = e.m_OffsetY; + + if (e.m_OffsetX > m_Max.m_X) m_Max.m_X = e.m_OffsetX; + + if (e.m_OffsetY > m_Max.m_Y) m_Max.m_Y = e.m_OffsetY; + } + } + + Center = new Point2D(-m_Min.m_X, -m_Min.m_Y); + Width = (m_Max.m_X - m_Min.m_X) + 1; + Height = (m_Max.m_Y - m_Min.m_Y) + 1; + + var tiles = new TileList[Width][]; + Tiles = new StaticTile[Width][][]; + + for (int x = 0; x < Width; ++x) + { + tiles[x] = new TileList[Height]; + Tiles[x] = new StaticTile[Height][]; + + for (int y = 0; y < Height; ++y) tiles[x][y] = new TileList(); + } + + for (int i = 0; i < allTiles.Length; ++i) + if (i == 0 || allTiles[i].m_Flags != 0) + { + int xOffset = allTiles[i].m_OffsetX + Center.m_X; + int yOffset = allTiles[i].m_OffsetY + Center.m_Y; + int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000); + + tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ); + } + + for (int x = 0; x < Width; ++x) + for (int y = 0; y < Height; ++y) + Tiles[x][y] = tiles[x][y].ToArray(); + } + private MultiComponentList() { Tiles = new StaticTile[0][][]; @@ -368,7 +538,7 @@ namespace Server for (int i = 0; i < oldList.Length; ++i) newList[i] = oldList[i]; - newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, 1); + newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, TileFlag.Background); List = newList; @@ -552,7 +722,7 @@ namespace Server if (vy > m_Max.m_Y) m_Max.m_Y = vy; - List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, 1); + List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, TileFlag.Background); } } } @@ -578,8 +748,86 @@ namespace Server writer.Write(ent.m_OffsetX); writer.Write(ent.m_OffsetY); writer.Write(ent.m_OffsetZ); - writer.Write(ent.m_Flags); + writer.Write((int)ent.m_Flags); } } } -} \ No newline at end of file + + public static class UOPHash + { + public static void BuildChunkIDs(out Dictionary chunkIds) + { + const int maxId = 0x10000; + + chunkIds = new Dictionary(); + + for (int i = 0; i < maxId; ++i) + chunkIds[HashLittle2($"build/multicollection/{i:000000}.bin")] = i; + } + + private static ulong HashLittle2(string s) + { + int length = s.Length; + + uint b, c; + uint a = b = c = 0xDEADBEEF + (uint)length; + + int k = 0; + + while (length > 12) + { + a += s[k]; + a += (uint)s[k + 1] << 8; + a += (uint)s[k + 2] << 16; + a += (uint)s[k + 3] << 24; + b += s[k + 4]; + b += (uint)s[k + 5] << 8; + b += (uint)s[k + 6] << 16; + b += (uint)s[k + 7] << 24; + c += s[k + 8]; + c += (uint)s[k + 9] << 8; + c += (uint)s[k + 10] << 16; + c += (uint)s[k + 11] << 24; + + a -= c; a ^= (c << 4) | (c >> 28); c += b; + b -= a; b ^= (a << 6) | (a >> 26); a += c; + c -= b; c ^= (b << 8) | (b >> 24); b += a; + a -= c; a ^= (c << 16) | (c >> 16); c += b; + b -= a; b ^= (a << 19) | (a >> 13); a += c; + c -= b; c ^= (b << 4) | (b >> 28); b += a; + + length -= 12; + k += 12; + } + + if (length != 0) + { + switch (length) + { + case 12: c += (uint)s[k + 11] << 24; goto case 11; + case 11: c += (uint)s[k + 10] << 16; goto case 10; + case 10: c += (uint)s[k + 9] << 8; goto case 9; + case 9: c += s[k + 8]; goto case 8; + case 8: b += (uint)s[k + 7] << 24; goto case 7; + case 7: b += (uint)s[k + 6] << 16; goto case 6; + case 6: b += (uint)s[k + 5] << 8; goto case 5; + case 5: b += s[k + 4]; goto case 4; + case 4: a += (uint)s[k + 3] << 24; goto case 3; + case 3: a += (uint)s[k + 2] << 16; goto case 2; + case 2: a += (uint)s[k + 1] << 8; goto case 1; + case 1: a += s[k]; break; + } + + c ^= b; c -= (b << 14) | (b >> 18); + a ^= c; a -= (c << 11) | (c >> 21); + b ^= a; b -= (a << 25) | (a >> 7); + c ^= b; c -= (b << 16) | (b >> 16); + a ^= c; a -= (c << 4) | (c >> 28); + b ^= a; b -= (a << 14) | (a >> 18); + c ^= b; c -= (b << 24) | (b >> 8); + } + + return ((ulong)b << 32) | c; + } + } +} diff --git a/Projects/Server/Network/MessagePumpService.cs b/Projects/Server/Network/MessagePumpService.cs index aaaac3a0b..a4a38afd3 100644 --- a/Projects/Server/Network/MessagePumpService.cs +++ b/Projects/Server/Network/MessagePumpService.cs @@ -1,23 +1,23 @@ - -/*************************************************************************** - * MessagePump.cs - * ------------------- - * begin : May 1, 2002 - * copyright : (C) The RunUO Software Team - * email : info@runuo.com - * - * $Id$ - * - ***************************************************************************/ - -/*************************************************************************** - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - ***************************************************************************/ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: MessagePumpService.cs * + * Created: 2020/04/12 - Updated: 2020/04/12 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ using System.Buffers; using System.Collections.Concurrent; diff --git a/Projects/Server/Network/NetState.cs b/Projects/Server/Network/NetState.cs index 3f9d9fc10..3288a5e71 100644 --- a/Projects/Server/Network/NetState.cs +++ b/Projects/Server/Network/NetState.cs @@ -285,7 +285,6 @@ namespace Server.Network public static int MenuCap { get; set; } = 512; - public void WriteConsole(string text) { Console.WriteLine("Client: {0}: {1}", this, text); @@ -395,8 +394,8 @@ namespace Server.Network public IAccount Account { get; set; } public override string ToString() => m_ToString; - public NetState(ConnectionContext connection) + { Connection = connection; Seeded = false; diff --git a/Projects/Server/Network/PacketHandlers.cs b/Projects/Server/Network/PacketHandlers.cs index a47cf99da..f35cc39e0 100644 --- a/Projects/Server/Network/PacketHandlers.cs +++ b/Projects/Server/Network/PacketHandlers.cs @@ -157,6 +157,8 @@ namespace Server.Network Register(0xD7, 0, true, EncodedCommand); Register(0xE1, 0, false, ClientType); Register(0xEF, 21, false, LoginServerSeed); + Register(0xEC, 0, false, EquipMacro); + Register(0xED, 0, false, UnequipMacro); Register(0xF4, 0, false, CrashReport); Register(0xF8, 106, false, CreateCharacter70160); Register(0xFB, 2, false, ShowPublicHouseContent); @@ -179,6 +181,9 @@ namespace Server.Network RegisterExtended(0x1C, true, CastSpell); RegisterExtended(0x24, false, UnhandledBF); RegisterExtended(0x2C, true, BandageTarget); + RegisterExtended(0x2D, true, TargetedSpell); + RegisterExtended(0x2E, true, TargetedSkillUse); + RegisterExtended(0x30, true, TargetByResourceMacro); RegisterExtended(0x32, true, ToggleFlying); RegisterEncoded(0x19, true, SetAbility); @@ -289,6 +294,8 @@ namespace Server.Network return -1; } + Console.WriteLine("Processing Packet... {0:X}", packetId); + if (!ns.Seeded) { if (packetId == 0xEF) @@ -381,17 +388,17 @@ namespace Server.Network public static void SetAbility(NetState state, IEntity e, EncodedReader reader) { - EventSink.InvokeSetAbility(new SetAbilityEventArgs(state.Mobile, reader.ReadInt32())); + EventSink.InvokeSetAbility(state.Mobile, reader.ReadInt32()); } public static void GuildGumpRequest(NetState state, IEntity e, EncodedReader reader) { - EventSink.InvokeGuildGumpRequest(new GuildGumpRequestArgs(state.Mobile)); + EventSink.InvokeGuildGumpRequest(state.Mobile); } public static void QuestGumpRequest(NetState state, IEntity e, EncodedReader reader) { - EventSink.InvokeQuestGumpRequest(new QuestGumpRequestArgs(state.Mobile)); + EventSink.InvokeQuestGumpRequest(state.Mobile); } public static void EncodedCommand(NetState state, PacketReader pvSrc) @@ -431,12 +438,12 @@ namespace Server.Network Mobile targ = World.FindMobile(pvSrc.ReadUInt32()); if (targ != null) - EventSink.InvokeRenameRequest(new RenameRequestEventArgs(from, targ, pvSrc.ReadStringSafe())); + EventSink.InvokeRenameRequest(from, targ, pvSrc.ReadStringSafe()); } public static void ChatRequest(NetState state, PacketReader pvSrc) { - EventSink.InvokeChatRequest(new ChatRequestEventArgs(state.Mobile)); + EventSink.InvokeChatRequest(state.Mobile); } public static void SecureTrade(NetState state, PacketReader pvSrc) @@ -591,7 +598,7 @@ namespace Server.Network pvSrc.Seek(30, SeekOrigin.Current); int index = pvSrc.ReadInt32(); - EventSink.InvokeDeleteRequest(new DeleteRequestEventArgs(state, index)); + EventSink.InvokeDeleteRequest(state, index); } public static void DeathStatusResponse(NetState state, PacketReader pvSrc) @@ -697,7 +704,7 @@ namespace Server.Network { case 0xC7: // Animate { - EventSink.InvokeAnimateRequest(new AnimateRequestEventArgs(m, command)); + EventSink.InvokeAnimateRequest(m, command); break; } @@ -715,7 +722,7 @@ namespace Server.Network if (!int.TryParse(command, out int booktype)) booktype = 1; - EventSink.InvokeOpenSpellbookRequest(new OpenSpellbookRequestEventArgs(m, booktype)); + EventSink.InvokeOpenSpellbookRequest(m, booktype); break; } @@ -728,14 +735,14 @@ namespace Server.Network int spellID = Utility.ToInt32(split[0]) - 1; uint serial = split.Length > 1 ? Utility.ToUInt32(split[1]) : (uint)Serial.MinusOne; - EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, World.FindItem(serial))); + EventSink.InvokeCastSpellRequest(m, spellID, World.FindItem(serial)); } break; } case 0x58: // Open door { - EventSink.InvokeOpenDoorMacroUsed(new OpenDoorMacroEventArgs(m)); + EventSink.InvokeOpenDoorMacroUsed(m); break; } @@ -743,7 +750,7 @@ namespace Server.Network { int spellID = Utility.ToInt32(command) - 1; - EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(m, spellID, null)); + EventSink.InvokeCastSpellRequest(m, spellID, null); break; } @@ -751,7 +758,7 @@ namespace Server.Network { int virtueID = Utility.ToInt32(command) - 1; - EventSink.InvokeVirtueMacroRequest(new VirtueMacroRequestEventArgs(m, virtueID)); + EventSink.InvokeVirtueMacroRequest(m, virtueID); break; } @@ -863,7 +870,7 @@ namespace Server.Network { case 0x00: // display request { - EventSink.InvokeProfileRequest(new ProfileRequestEventArgs(beholder, beheld)); + EventSink.InvokeProfileRequest(beholder, beheld); break; } @@ -877,7 +884,7 @@ namespace Server.Network string text = pvSrc.ReadUnicodeString(length); - EventSink.InvokeChangeProfileRequest(new ChangeProfileRequestEventArgs(beholder, beheld, text)); + EventSink.InvokeChangeProfileRequest(beholder, beheld, text); break; } @@ -1011,7 +1018,7 @@ namespace Server.Network public static void HelpRequest(NetState state, PacketReader pvSrc) { - EventSink.InvokeHelpRequest(new HelpRequestEventArgs(state.Mobile)); + EventSink.InvokeHelpRequest(state.Mobile); } public static void TargetResponse(NetState state, PacketReader pvSrc) @@ -1216,14 +1223,14 @@ namespace Server.Network Mobile beheld = World.FindMobile(pvSrc.ReadUInt32()); if (beheld != null) - EventSink.InvokeVirtueGumpRequest(new VirtueGumpRequestEventArgs(state.Mobile, beheld)); + EventSink.InvokeVirtueGumpRequest(state.Mobile, beheld); } else { Mobile beheld = World.FindMobile(serial); if (beheld != null) - EventSink.InvokeVirtueItemRequest(new VirtueItemRequestEventArgs(state.Mobile, beheld, buttonID)); + EventSink.InvokeVirtueItemRequest(state.Mobile, beheld, buttonID); } } } @@ -1513,7 +1520,7 @@ namespace Server.Network int spellID = pvSrc.ReadInt16() - 1; - EventSink.InvokeCastSpellRequest(new CastSpellRequestEventArgs(from, spellID, spellbook)); + EventSink.InvokeCastSpellRequest(from, spellID, spellbook); } public static void BandageTarget(NetState state, PacketReader pvSrc) @@ -1535,7 +1542,7 @@ namespace Server.Network if (target == null) return; - EventSink.InvokeBandageTargetRequest(new BandageTargetRequestEventArgs(from, bandage, target)); + EventSink.InvokeBandageTargetRequest(from, bandage, target); from.NextActionTime = Core.TickCount + Mobile.ActionDelay; } @@ -1691,12 +1698,12 @@ namespace Server.Network public static void StunRequest(NetState state, PacketReader pvSrc) { - EventSink.InvokeStunRequest(new StunRequestEventArgs(state.Mobile)); + EventSink.InvokeStunRequest(state.Mobile); } public static void DisarmRequest(NetState state, PacketReader pvSrc) { - EventSink.InvokeDisarmRequest(new DisarmRequestEventArgs(state.Mobile)); + EventSink.InvokeDisarmRequest(state.Mobile); } public static void StatLockChange(NetState state, PacketReader pvSrc) @@ -1828,7 +1835,7 @@ namespace Server.Network { CV version = state.Version = new CV(pvSrc.ReadString()); - EventSink.InvokeClientVersionReceived(new ClientVersionReceivedArgs(state, version)); + EventSink.InvokeClientVersionReceived(state, version); } public static void ClientType(NetState state, PacketReader pvSrc) @@ -1838,7 +1845,7 @@ namespace Server.Network int type = pvSrc.ReadUInt16(); CV version = state.Version = new CV(pvSrc.ReadString()); - //EventSink.InvokeClientVersionReceived( new ClientVersionReceivedArgs( state, version ) );//todo + EventSink.InvokeClientVersionReceived(state, version); } public static void MobileQuery(NetState state, PacketReader pvSrc) @@ -2025,7 +2032,7 @@ namespace Server.Network state.Send(SeasonChange.Instantiate(m.GetSeason(), true)); state.Send(new MapChange(m)); - EventSink.InvokeLogin(new LoginEventArgs(m)); + EventSink.InvokeLogin(m); m.ClearFastwalkStack(); } @@ -2493,6 +2500,47 @@ namespace Server.Network state.Dispose(); } + public static void EquipMacro(NetState ns, PacketReader pvSrc) + { + int count = pvSrc.ReadByte(); + List serialList = new List(count); + for (int i = 0; i < count; ++i) + serialList.Add(pvSrc.ReadUInt32()); + + EventSink.InvokeEquipMacro(ns.Mobile, serialList); + } + + public static void UnequipMacro(NetState ns, PacketReader pvSrc) + { + int count = pvSrc.ReadByte(); + List layers = new List(count); + for (int i = 0; i < count; ++i) + layers.Add((Layer)pvSrc.ReadUInt16()); + + EventSink.InvokeUnequipMacro(ns.Mobile, layers); + } + + public static void TargetedSpell(NetState ns, PacketReader pvSrc) + { + short spellId = (short)(pvSrc.ReadInt16() - 1); // zero based; + + EventSink.InvokeTargetedSpell(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), spellId); + } + + public static void TargetedSkillUse(NetState ns, PacketReader pvSrc) + { + short skillId = pvSrc.ReadInt16(); + + EventSink.InvokeTargetedSkillUse(ns.Mobile, World.FindEntity(pvSrc.ReadUInt32()), skillId); + } + + public static void TargetByResourceMacro(NetState ns, PacketReader pvSrc) + { + Serial serial = pvSrc.ReadUInt32(); + + if (serial.IsItem) EventSink.InvokeTargetByResourceMacro(ns.Mobile, World.FindItem(serial), pvSrc.ReadInt16()); + } + private class LoginTimer : Timer { private readonly Mobile m_Mobile; diff --git a/Projects/Server/Network/UOConnectionHandler.cs b/Projects/Server/Network/ServerConnectionHandler.cs similarity index 61% rename from Projects/Server/Network/UOConnectionHandler.cs rename to Projects/Server/Network/ServerConnectionHandler.cs index 75f24c1ef..ed2137de9 100644 --- a/Projects/Server/Network/UOConnectionHandler.cs +++ b/Projects/Server/Network/ServerConnectionHandler.cs @@ -1,3 +1,24 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ServerConnectionHandler.cs * + * Created: 2020/04/12 - Updated: 2020/04/12 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + using System; using System.Buffers; using System.IO.Pipelines; diff --git a/Projects/Server/Network/ServerStartup.cs b/Projects/Server/Network/ServerStartup.cs index d0f0324c5..37e3797df 100644 --- a/Projects/Server/Network/ServerStartup.cs +++ b/Projects/Server/Network/ServerStartup.cs @@ -1,7 +1,27 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: ServerStartup.cs * + * Created: 2020/04/12 - Updated: 2020/04/12 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + using System.Threading.Tasks; using Microsoft.AspNetCore.Builder; using Microsoft.Extensions.DependencyInjection; -using Server.Network; namespace Server.Network { diff --git a/Projects/Server/Network/TcpServer.cs b/Projects/Server/Network/TcpServer.cs index 270beec52..ab14fc2c7 100644 --- a/Projects/Server/Network/TcpServer.cs +++ b/Projects/Server/Network/TcpServer.cs @@ -1,3 +1,24 @@ +/************************************************************************* + * ModernUO * + * Copyright (C) 2019 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: TcpServer.cs * + * Created: 2020/04/12 - Updated: 2020/04/12 * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * This program is distributed in the hope that it will be useful, * + * but WITHOUT ANY WARRANTY; without even the implied warranty of * + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * + * GNU General Public License for more details. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ + using System; using System.Collections.Generic; using System.Net; diff --git a/Projects/Server/Persistence/StandardSaveStrategy.cs b/Projects/Server/Persistence/StandardSaveStrategy.cs index d75403754..282905229 100644 --- a/Projects/Server/Persistence/StandardSaveStrategy.cs +++ b/Projects/Server/Persistence/StandardSaveStrategy.cs @@ -49,11 +49,7 @@ namespace Server { PermitBackgroundWrite = permitBackgroundWrite; - Task.WaitAll(new Task[3] { - Task.Factory.StartNew(() => SaveMobiles()), - Task.Factory.StartNew(() => SaveItems()), - Task.Factory.StartNew(() => SaveGuilds()) - }); + Task.WaitAll(Task.Factory.StartNew(SaveMobiles), Task.Factory.StartNew(SaveItems), Task.Factory.StartNew(SaveGuilds)); if (permitBackgroundWrite && UseSequentialWriters ) //If we're permitted to write in the background, but we don't anyways, then notify. @@ -155,7 +151,10 @@ namespace Server foreach (Item item in items.Values) { if (item.Decays && item.Parent == null && item.Map != Map.Internal && item.LastMoved + item.DecayTime <= n) + { + Console.WriteLine($"Decay Item {item.Name ?? item.DefaultName} ({item.GetType().FullName})"); _decayQueue.Enqueue(item); + } long start = bin.Position; @@ -217,7 +216,8 @@ namespace Server { Item item = _decayQueue.Dequeue(); - if (item.OnDecay()) item.Delete(); + if (item.OnDecay()) + item.Delete(); } } } diff --git a/Projects/Server/TileData.cs b/Projects/Server/TileData.cs index 0865840b8..448409fbe 100644 --- a/Projects/Server/TileData.cs +++ b/Projects/Server/TileData.cs @@ -183,116 +183,7 @@ namespace Server { string filePath = Core.FindDataFile("tiledata.mul"); - if (File.Exists(filePath)) - { - using (FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read)) - { - BinaryReader bin = new BinaryReader(fs); - - if (fs.Length == 3188736) - { - // 7.0.9.0 - LandTable = new LandData[0x4000]; - - for (int i = 0; i < 0x4000; ++i) - { - if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header - - TileFlag flags = (TileFlag)bin.ReadInt64(); - bin.ReadInt16(); // skip 2 bytes -- textureID - - LandTable[i] = new LandData(ReadNameString(bin), flags); - } - - ItemTable = new ItemData[0x10000]; - - for (int i = 0; i < 0x10000; ++i) - { - if ((i & 0x1F) == 0) bin.ReadInt32(); // header - - TileFlag flags = (TileFlag)bin.ReadInt64(); - int weight = bin.ReadByte(); - int quality = bin.ReadByte(); - bin.ReadInt16(); - bin.ReadByte(); - int quantity = bin.ReadByte(); - bin.ReadInt32(); - bin.ReadByte(); - int value = bin.ReadByte(); - int height = bin.ReadByte(); - - ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, - height); - } - } - else - { - LandTable = new LandData[0x4000]; - - for (int i = 0; i < 0x4000; ++i) - { - if ((i & 0x1F) == 0) bin.ReadInt32(); // header - - TileFlag flags = (TileFlag)bin.ReadInt32(); - bin.ReadInt16(); // skip 2 bytes -- textureID - - LandTable[i] = new LandData(ReadNameString(bin), flags); - } - - if (fs.Length == 1644544) - { - // 7.0.0.0 - ItemTable = new ItemData[0x8000]; - - for (int i = 0; i < 0x8000; ++i) - { - if ((i & 0x1F) == 0) bin.ReadInt32(); // header - - TileFlag flags = (TileFlag)bin.ReadInt32(); - int weight = bin.ReadByte(); - int quality = bin.ReadByte(); - bin.ReadInt16(); - bin.ReadByte(); - int quantity = bin.ReadByte(); - bin.ReadInt32(); - bin.ReadByte(); - int value = bin.ReadByte(); - int height = bin.ReadByte(); - - ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, - height); - } - } - else - { - ItemTable = new ItemData[0x4000]; - - for (int i = 0; i < 0x4000; ++i) - { - if ((i & 0x1F) == 0) bin.ReadInt32(); // header - - TileFlag flags = (TileFlag)bin.ReadInt32(); - int weight = bin.ReadByte(); - int quality = bin.ReadByte(); - bin.ReadInt16(); - bin.ReadByte(); - int quantity = bin.ReadByte(); - bin.ReadInt32(); - bin.ReadByte(); - int value = bin.ReadByte(); - int height = bin.ReadByte(); - - ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, - height); - } - } - } - } - - MaxLandValue = LandTable.Length - 1; - MaxItemValue = ItemTable.Length - 1; - } - else + if (!File.Exists(filePath)) { Console.ForegroundColor = ConsoleColor.Red; Console.WriteLine("tiledata.mul was not found"); @@ -302,6 +193,111 @@ namespace Server throw new Exception($"TileData: {filePath} not found"); } + + using FileStream fs = new FileStream(filePath, FileMode.Open, FileAccess.Read, FileShare.Read); + BinaryReader bin = new BinaryReader(fs); + + if (fs.Length == 3188736) + { + // 7.0.9.0 + LandTable = new LandData[0x4000]; + + for (int i = 0; i < 0x4000; ++i) + { + if (i == 1 || i > 0 && (i & 0x1F) == 0) bin.ReadInt32(); // header + + TileFlag flags = (TileFlag)bin.ReadInt64(); + bin.ReadInt16(); // skip 2 bytes -- textureID + + LandTable[i] = new LandData(ReadNameString(bin), flags); + } + + ItemTable = new ItemData[0x10000]; + + for (int i = 0; i < 0x10000; ++i) + { + if ((i & 0x1F) == 0) bin.ReadInt32(); // header + + TileFlag flags = (TileFlag)bin.ReadInt64(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, + height); + } + } + else + { + LandTable = new LandData[0x4000]; + + for (int i = 0; i < 0x4000; ++i) + { + if ((i & 0x1F) == 0) bin.ReadInt32(); // header + + TileFlag flags = (TileFlag)bin.ReadInt32(); + bin.ReadInt16(); // skip 2 bytes -- textureID + + LandTable[i] = new LandData(ReadNameString(bin), flags); + } + + if (fs.Length == 1644544) + { + // 7.0.0.0 + ItemTable = new ItemData[0x8000]; + + for (int i = 0; i < 0x8000; ++i) + { + if ((i & 0x1F) == 0) bin.ReadInt32(); // header + + TileFlag flags = (TileFlag)bin.ReadInt32(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, + height); + } + } + else + { + ItemTable = new ItemData[0x4000]; + + for (int i = 0; i < 0x4000; ++i) + { + if ((i & 0x1F) == 0) bin.ReadInt32(); // header + + TileFlag flags = (TileFlag)bin.ReadInt32(); + int weight = bin.ReadByte(); + int quality = bin.ReadByte(); + bin.ReadInt16(); + bin.ReadByte(); + int quantity = bin.ReadByte(); + bin.ReadInt32(); + bin.ReadByte(); + int value = bin.ReadByte(); + int height = bin.ReadByte(); + + ItemTable[i] = new ItemData(ReadNameString(bin), flags, weight, quality, quantity, value, + height); + } + } + } + + MaxLandValue = LandTable.Length - 1; + MaxItemValue = ItemTable.Length - 1; } public static LandData[] LandTable{ get; } diff --git a/Projects/Server/TileMatrix.cs b/Projects/Server/TileMatrix.cs index d45da5ac3..22429b7f5 100644 --- a/Projects/Server/TileMatrix.cs +++ b/Projects/Server/TileMatrix.cs @@ -34,6 +34,14 @@ namespace Server private readonly int m_FileIndex; private readonly List m_FileShare = new List(); + private readonly FileStream m_MapStream; + + public FileStream IndexStream { get; } + + public FileStream DataStream { get; } + + private readonly BinaryReader m_IndexReader; + private readonly LandTile[] m_InvalidLandBlock; private readonly int[][] m_LandPatches; private readonly LandTile[][][] m_LandTiles; @@ -53,7 +61,6 @@ namespace Server private StaticTile[] m_TileBuffer = new StaticTile[128]; private readonly TileList m_TilesList = new TileList(); - // private int m_Width, m_Height; public TileMatrix(Map owner, int fileIndex, int mapID, int width, int height) { @@ -78,8 +85,6 @@ namespace Server } m_FileIndex = fileIndex; -// m_Width = width; -// m_Height = height; BlockWidth = width >> 3; BlockHeight = height >> 3; @@ -87,21 +92,19 @@ namespace Server if (fileIndex != 0x7F) { - string mapPath = Core.FindDataFile("map{0}.mul", fileIndex); + string mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex); if (File.Exists(mapPath)) { - MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); + m_MapIndex = new UOPIndex(m_MapStream); } else { - mapPath = Core.FindDataFile("map{0}LegacyMUL.uop", fileIndex); + mapPath = Core.FindDataFile("map{0}.mul", fileIndex); if (File.Exists(mapPath)) - { - MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - m_MapIndex = new UOPIndex(MapStream); - } + m_MapStream = new FileStream(mapPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); } string indexPath = Core.FindDataFile("staidx{0}.mul", fileIndex); @@ -109,7 +112,7 @@ namespace Server if (File.Exists(indexPath)) { IndexStream = new FileStream(indexPath, FileMode.Open, FileAccess.Read, FileShare.ReadWrite); - IndexReader = new BinaryReader(IndexStream); + m_IndexReader = new BinaryReader(IndexStream); } string staticsPath = Core.FindDataFile("statics{0}.mul", fileIndex); @@ -138,51 +141,12 @@ namespace Server Patch = new TileMatrixPatch(this, mapID); } - /*public Map Owner - { - get - { - return m_Owner; - } - }*/ - public TileMatrixPatch Patch{ get; } public int BlockWidth{ get; } public int BlockHeight{ get; } - /*public int Width - { - get - { - return m_Width; - } - } - - public int Height - { - get - { - return m_Height; - } - }*/ - - public FileStream MapStream{ get; set; } - - /*public bool MapUOPPacked - { - get{ return ( m_MapIndex != null ); } - }*/ - - public FileStream IndexStream{ get; set; } - - public FileStream DataStream{ get; set; } - - public BinaryReader IndexReader{ get; set; } - - public bool Exists => MapStream != null && IndexStream != null && DataStream != null; - public StaticTile[][][] EmptyStaticBlock{ get; } [MethodImpl(MethodImplOptions.Synchronized)] @@ -292,7 +256,7 @@ namespace Server [MethodImpl(MethodImplOptions.Synchronized)] public LandTile[] GetLandBlock(int x, int y) { - if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || MapStream == null) + if (x < 0 || y < 0 || x >= BlockWidth || y >= BlockHeight || m_MapStream == null) return m_InvalidLandBlock; m_LandTiles[x] ??= new LandTile[BlockHeight][]; @@ -339,10 +303,10 @@ namespace Server { try { - IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin); + m_IndexReader.BaseStream.Seek((x * BlockHeight + y) * 12, SeekOrigin.Begin); - int lookup = IndexReader.ReadInt32(); - int length = IndexReader.ReadInt32(); + int lookup = m_IndexReader.ReadInt32(); + int length = m_IndexReader.ReadInt32(); if (lookup < 0 || length <= 0) return EmptyStaticBlock; @@ -423,13 +387,13 @@ namespace Server if (m_MapIndex != null) offset = m_MapIndex.Lookup(offset); - MapStream.Seek(offset, SeekOrigin.Begin); + m_MapStream.Seek(offset, SeekOrigin.Begin); LandTile[] tiles = new LandTile[64]; fixed (LandTile* pTiles = tiles) { - NativeReader.Read(MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192); + NativeReader.Read(m_MapStream.SafeFileHandle.DangerousGetHandle(), pTiles, 192); } return tiles; @@ -448,14 +412,10 @@ namespace Server public void Dispose() { - if (m_MapIndex != null) - m_MapIndex.Close(); - else - MapStream?.Close(); - + m_MapIndex?.Close(); + m_MapStream?.Close(); DataStream?.Close(); - - IndexReader?.Close(); + m_IndexReader?.Close(); } } @@ -670,16 +630,8 @@ namespace Server { public static readonly IComparer Instance = new OffsetComparer(); - public int Compare(UOPEntry x, UOPEntry y) - { - if (x == null) - return y == null ? 0 : 1; - - if (y == null) - return -1; - - return x.m_Offset.CompareTo(y.m_Offset); - } + public int Compare(UOPEntry x, UOPEntry y) => + x == null ? y == null ? 0 : 1 : y == null ? -1 : x.m_Offset.CompareTo(y.m_Offset); } } } diff --git a/Projects/Server/Utilities/Xoshiro256PlusPlus.cs b/Projects/Server/Utilities/Xoshiro256PlusPlus.cs index e436fe314..e718b694b 100644 --- a/Projects/Server/Utilities/Xoshiro256PlusPlus.cs +++ b/Projects/Server/Utilities/Xoshiro256PlusPlus.cs @@ -19,8 +19,6 @@ * along with this program. If not, see . * *************************************************************************/ -#nullable enable - using System; using System.Runtime.CompilerServices; using System.Security.Cryptography; diff --git a/Projects/Server/World.cs b/Projects/Server/World.cs index d4c75c5ae..4602c7a66 100644 --- a/Projects/Server/World.cs +++ b/Projects/Server/World.cs @@ -645,7 +645,7 @@ namespace Server try { - EventSink.InvokeWorldSave(new WorldSaveEventArgs(message)); + EventSink.InvokeWorldSave(message); } catch (Exception e) { diff --git a/THIRD-PARTY-NOTICES b/THIRD-PARTY-NOTICES index 9035bfbd9..0e65567e8 100644 --- a/THIRD-PARTY-NOTICES +++ b/THIRD-PARTY-NOTICES @@ -579,3 +579,25 @@ proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. + +The MIT License (MIT) + +Copyright (c) Harry Pierson + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE.