From 6fe01488eff759a21dab50e6a94103673f83dcf6 Mon Sep 17 00:00:00 2001 From: Stefano Merotta <97297186+stefanomerotta@users.noreply.github.com> Date: Sat, 10 Aug 2024 18:57:28 +0200 Subject: [PATCH] fix: Fix NetStateGumps and other Gumps cleanup (#1919) --- .../Engines/ConPVP/AcceptDuelGump.cs | 2 +- .../UOContent/Engines/ConPVP/DuelContext.cs | 6 +- .../Gumps/Base/GumpSystem.IncomingPackets.cs | 15 +- Projects/UOContent/Gumps/Base/GumpSystem.cs | 146 ++---------------- .../UOContent/Gumps/Base/NetStateGumps.cs | 42 ++++- .../UOContent/Gumps/PricedResurrectGump.cs | 5 +- Projects/UOContent/Mobiles/PlayerMobile.cs | 15 +- 7 files changed, 73 insertions(+), 158 deletions(-) diff --git a/Projects/UOContent/Engines/ConPVP/AcceptDuelGump.cs b/Projects/UOContent/Engines/ConPVP/AcceptDuelGump.cs index c705587c1..00a2bf29e 100644 --- a/Projects/UOContent/Engines/ConPVP/AcceptDuelGump.cs +++ b/Projects/UOContent/Engines/ConPVP/AcceptDuelGump.cs @@ -244,7 +244,7 @@ namespace Server.Engines.ConPVP m_Challenger.SendMessage($"{m_Challenged.Name} has accepted the request."); m_Challenged.SendMessage($"You have accepted the request from {m_Challenger.Name}."); - foreach (var g in m_Challenger.GetAllGumps()) + foreach (var g in m_Challenger.GetGumps()) { if (g is ParticipantGump pg && pg.Participant == m_Participant) { diff --git a/Projects/UOContent/Engines/ConPVP/DuelContext.cs b/Projects/UOContent/Engines/ConPVP/DuelContext.cs index bbb8986d6..c44bb85c2 100644 --- a/Projects/UOContent/Engines/ConPVP/DuelContext.cs +++ b/Projects/UOContent/Engines/ConPVP/DuelContext.cs @@ -1541,7 +1541,7 @@ namespace Server.Engines.ConPVP p.Nullify(pl); pm.DuelPlayer = null; - foreach (var g in init.GetAllGumps()) + foreach (var g in init.GetGumps()) { if (g is ParticipantGump pg && pg.Participant == p) { @@ -1576,7 +1576,7 @@ namespace Server.Engines.ConPVP var send = true; - foreach (var g in init.GetAllGumps()) + foreach (var g in init.GetGumps()) { if (g is ParticipantGump pg && pg.Participant == p) { @@ -1620,7 +1620,7 @@ namespace Server.Engines.ConPVP var send = true; - foreach (var g in init.GetAllGumps()) + foreach (var g in init.GetGumps()) { if (g is ParticipantGump pg && pg.Participant == p) { diff --git a/Projects/UOContent/Gumps/Base/GumpSystem.IncomingPackets.cs b/Projects/UOContent/Gumps/Base/GumpSystem.IncomingPackets.cs index ca4f5e968..e1d6d033b 100644 --- a/Projects/UOContent/Gumps/Base/GumpSystem.IncomingPackets.cs +++ b/Projects/UOContent/Gumps/Base/GumpSystem.IncomingPackets.cs @@ -37,15 +37,18 @@ public static partial class GumpSystem BaseGump baseGump = null; - foreach (var g in GetAll(state)) + if (_gumps.TryGetValue(state, out var gumps)) { - if (g.Serial != serial || g.TypeID != typeId) + foreach (var g in gumps) { - continue; - } + if (g.Serial != serial || g.TypeID != typeId) + { + continue; + } - baseGump = g; - break; + baseGump = g; + break; + } } if (baseGump != null) diff --git a/Projects/UOContent/Gumps/Base/GumpSystem.cs b/Projects/UOContent/Gumps/Base/GumpSystem.cs index fa96b627d..957f31852 100644 --- a/Projects/UOContent/Gumps/Base/GumpSystem.cs +++ b/Projects/UOContent/Gumps/Base/GumpSystem.cs @@ -13,8 +13,6 @@ * along with this program. If not, see . * *************************************************************************/ -using Server.Gumps.Base; -using Server.Logging; using Server.Network; using System; using System.Collections.Generic; @@ -26,11 +24,9 @@ namespace Server.Gumps; public static partial class GumpSystem { - private const int GumpCap = 512; - private const int InitialCapacity = 4; + public const int GumpCap = 512; private static readonly Dictionary> _gumps = []; - private static readonly ILogger _logger = LogFactory.GetLogger(typeof(GumpSystem)); public static unsafe void Configure() { @@ -47,51 +43,7 @@ public static partial class GumpSystem } } - private static ReadOnlySpan GetAll(NetState ns) => - _gumps.TryGetValue(ns, out var gumps) ? CollectionsMarshal.AsSpan(gumps) : []; - - private static T Find(NetState ns) where T : BaseGump - { - if (ns == null || !_gumps.TryGetValue(ns, out var gumps)) - { - return null; - } - - var gumpsSpan = CollectionsMarshal.AsSpan(gumps); - for (int i = 0; i < gumpsSpan.Length; i++) - { - if (gumpsSpan[i] is T tGump) - { - return tGump; - } - } - - return null; - } - - private static void Add(NetState ns, BaseGump gump) - { - if (ns == null || gump == null) - { - return; - } - - if (!_gumps.TryGetValue(ns, out var gumps)) - { - gumps = new List(InitialCapacity); - _gumps.Add(ns, gumps); - } - - if (gumps.Count < GumpCap) - { - gumps.Add(gump); - } - else - { - _logger.Information("Exceeded gump cap, disconnecting..."); - ns.Disconnect("Exceeded gump cap."); - } - } + private static T Find(NetState ns) where T : BaseGump => ns != null ? Get(ns).Find() : null; private static void Remove(NetState ns, BaseGump gump) { @@ -108,26 +60,6 @@ public static partial class GumpSystem } } - private static bool Remove(NetState ns, out T gump) where T : BaseGump - { - if (ns != null && _gumps.TryGetValue(ns, out var gumps)) - { - var gumpsSpan = CollectionsMarshal.AsSpan(gumps); - for (int i = 0; i < gumpsSpan.Length; i++) - { - if (gumpsSpan[i] is T tGump) - { - gumps.RemoveAt(i); - gump = tGump; - return true; - } - } - } - - gump = null; - return false; - } - private static void Send(NetState ns, BaseGump gump, bool singleton) { if (ns.CannotSendPackets()) // Handles ns null check too @@ -135,62 +67,16 @@ public static partial class GumpSystem return; } - ref List list = ref CollectionsMarshal.GetValueRefOrAddDefault(_gumps, ns, out bool exists); - - if (exists) - { - bool replaced = false; - - if (singleton || gump.Singleton) - { - for (int i = 0; i < list.Count; i++) - { - BaseGump old = list[i]; - - if (old.TypeID == gump.TypeID) - { - ns.SendCloseGump(old.TypeID, 0); - old.OnServerClose(ns); - - list[i] = gump; - replaced = true; - break; - } - } - } - - if (!replaced) - { - list.Add(gump); - } - } - else - { - list = [gump]; - } - - gump.SendTo(ns); + Get(ns).Send(gump, singleton); } - private static bool Close(NetState ns) where T : BaseGump - { - if (Remove(ns, out var gump)) - { - ns.SendCloseGump(gump.TypeID, 0); - gump.OnServerClose(ns); - return true; - } - - return false; - } - - private static readonly List _emptyList = []; + private static bool Close(NetState ns) where T : BaseGump => ns != null && Get(ns).Close(); private static NetStateGumps Get(NetState ns) { if (ns == null) { - return new NetStateGumps(_emptyList, null); + return new NetStateGumps(null, null); } ref List list = ref CollectionsMarshal.GetValueRefOrAddDefault(_gumps, ns, out bool exists); @@ -231,13 +117,6 @@ public static partial class GumpSystem Send(m.NetState, g, singleton); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan GetAllGumps([DisallowNull] this Mobile m) - { - ArgumentNullException.ThrowIfNull(m); - return GetAll(m.NetState); - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NetStateGumps GetGumps([DisallowNull] this Mobile m) { @@ -253,10 +132,10 @@ public static partial class GumpSystem } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void SendGump([DisallowNull] this NetState ns, BaseGump g, bool singleton = false) + public static T FindGump([DisallowNull] this NetState ns) where T : BaseGump { ArgumentNullException.ThrowIfNull(ns); - Send(ns, g, singleton); + return Find(ns); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -267,17 +146,10 @@ public static partial class GumpSystem } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ReadOnlySpan GetAllGumps([DisallowNull] this NetState ns) + public static void SendGump([DisallowNull] this NetState ns, BaseGump g, bool singleton = false) { ArgumentNullException.ThrowIfNull(ns); - return GetAll(ns); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static void AddGump([DisallowNull] this NetState ns, BaseGump gump) - { - ArgumentNullException.ThrowIfNull(ns); - Add(ns, gump); + Send(ns, g, singleton); } [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/Projects/UOContent/Gumps/Base/NetStateGumps.cs b/Projects/UOContent/Gumps/Base/NetStateGumps.cs index 626ee7fcd..61f47b3a0 100644 --- a/Projects/UOContent/Gumps/Base/NetStateGumps.cs +++ b/Projects/UOContent/Gumps/Base/NetStateGumps.cs @@ -1,10 +1,31 @@ -using Server.Network; -using System.Collections.Generic; +/************************************************************************* + * ModernUO * + * Copyright 2019-2023 - ModernUO Development Team * + * Email: hi@modernuo.com * + * File: NetStateGumps.cs * + * * + * This program is free software: you can redistribute it and/or modify * + * it under the terms of the GNU General Public License as published by * + * the Free Software Foundation, either version 3 of the License, or * + * (at your option) any later version. * + * * + * You should have received a copy of the GNU General Public License * + * along with this program. If not, see . * + *************************************************************************/ -namespace Server.Gumps.Base; +using Server.Logging; +using Server.Network; +using System; +using System.Collections.Generic; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace Server.Gumps; public readonly ref struct NetStateGumps { + private static readonly ILogger _logger = LogFactory.GetLogger(typeof(NetStateGumps)); + private readonly List _gumps; private readonly NetState _state; @@ -16,7 +37,7 @@ public readonly ref struct NetStateGumps public bool Close() where T : BaseGump { - if (_state == null || _gumps == null) + if (_state == null) { return false; } @@ -38,7 +59,7 @@ public readonly ref struct NetStateGumps public T Find() where T : BaseGump { - if (_state == null || _gumps == null) + if (_state == null) { return null; } @@ -81,7 +102,18 @@ public readonly ref struct NetStateGumps } } + if (_gumps.Count >= GumpSystem.GumpCap) + { + _logger.Information("Exceeded gump cap, disconnecting..."); + _state.Disconnect("Exceeded gump cap."); + return; + } + _gumps.Add(gump); gump.SendTo(_state); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public ReadOnlySpan.Enumerator GetEnumerator() => + ((ReadOnlySpan)CollectionsMarshal.AsSpan(_gumps)).GetEnumerator(); } diff --git a/Projects/UOContent/Gumps/PricedResurrectGump.cs b/Projects/UOContent/Gumps/PricedResurrectGump.cs index 205e9a12a..3d173c38b 100644 --- a/Projects/UOContent/Gumps/PricedResurrectGump.cs +++ b/Projects/UOContent/Gumps/PricedResurrectGump.cs @@ -15,7 +15,6 @@ public class PricedResurrectGump : StaticGump _healer = healer; _price = price; - // Close this gump when TypeID = GetTypeId(typeof(ResurrectGump)); } @@ -101,8 +100,8 @@ public class PricedResurrectGump : StaticGump if (Banker.Withdraw(from, _price)) { - // ~1_AMOUNT~ gold has been withdrawn from your bank box. - from.SendLocalizedMessage(1060398, _price.ToString()); + // ~1_AMOUNT~ gold has been withdrawn from your bank to cover the price of the healing. + from.SendLocalizedMessage(1060021, _price.ToString()); // You have ~1_AMOUNT~ gold in cash remaining in your bank box. from.SendLocalizedMessage(1060022, Banker.GetBalance(from).ToString()); diff --git a/Projects/UOContent/Mobiles/PlayerMobile.cs b/Projects/UOContent/Mobiles/PlayerMobile.cs index dd015ee04..b88f3a9fb 100644 --- a/Projects/UOContent/Mobiles/PlayerMobile.cs +++ b/Projects/UOContent/Mobiles/PlayerMobile.cs @@ -1723,10 +1723,19 @@ namespace Server.Mobiles public override bool Move(Direction d) { - if (NetState != null && Alive && !NetState.CloseGump()) + if (NetState != null) { - SendLocalizedMessage(500111); // You are frozen and cannot move. - return false; + var gumps = NetState.GetGumps(); + + if (Alive) + { + gumps.Close(); + } + else if (gumps.Has()) + { + SendLocalizedMessage(500111); // You are frozen and cannot move. + return false; + } } // var speed = ComputeMovementSpeed(d);