diff --git a/Scripts/Items/Weapons/BaseWeapon.cs b/Scripts/Items/Weapons/BaseWeapon.cs index 4cba6fc9a..cef3c423b 100644 --- a/Scripts/Items/Weapons/BaseWeapon.cs +++ b/Scripts/Items/Weapons/BaseWeapon.cs @@ -1315,7 +1315,8 @@ namespace Server.Items int inPack = 1; - foreach ( Mobile m in defender.GetMobilesInRange( 1 ) ) + IPooledEnumerable eable = defender.GetMobilesInRange( 1 ); + foreach ( Mobile m in eable ) { if ( m != attacker && m is BaseCreature ) { @@ -1333,6 +1334,7 @@ namespace Server.Items ++inPack; } } + eable.Free(); if ( inPack >= 5 ) return 100; @@ -1365,7 +1367,8 @@ namespace Server.Items { Clone bc; - foreach ( Mobile m in defender.GetMobilesInRange( 4 ) ) + IPooledEnumerable eable = defender.GetMobilesInRange( 4 ); + foreach ( Mobile m in eable) { bc = m as Clone; @@ -1384,6 +1387,7 @@ namespace Server.Items break; } } + eable.Free(); } PlaySwingAnimation( attacker ); @@ -1912,11 +1916,13 @@ namespace Server.Items int range = Core.ML ? 5 : 10; - foreach ( Mobile m in from.GetMobilesInRange( range ) ) + IPooledEnumerable eable = from.GetMobilesInRange(range); + foreach ( Mobile m in eable ) { if ( from != m && defender != m && SpellHelper.ValidIndirectTarget( from, m ) && from.CanBeHarmful( m, false ) && ( !Core.ML || from.InLOS( m ) ) ) list.Add( m ); } + eable.Free(); if ( list.Count == 0 ) return; diff --git a/Scripts/Misc/Notoriety.cs b/Scripts/Misc/Notoriety.cs index e384f1fc5..2e4c321a2 100644 --- a/Scripts/Misc/Notoriety.cs +++ b/Scripts/Misc/Notoriety.cs @@ -365,6 +365,8 @@ namespace Server.Misc } } + /* Must be thread-safe */ + public static int MobileNotoriety( Mobile source, Mobile target ) { if ( Core.AOS && ( target.Blessed || ( target is BaseCreature && ( (BaseCreature)target ).IsInvulnerable ) || target is PlayerVendor || target is TownCrier ) ) diff --git a/Scripts/Mobiles/AI/BaseAI.cs b/Scripts/Mobiles/AI/BaseAI.cs index 48793bc06..31f00081e 100644 --- a/Scripts/Mobiles/AI/BaseAI.cs +++ b/Scripts/Mobiles/AI/BaseAI.cs @@ -2632,7 +2632,8 @@ namespace Server.Mobiles if (srcSkill <= 0) return; - foreach (Mobile trg in m_Mobile.GetMobilesInRange(m_Mobile.RangePerception)) + IPooledEnumerable eable = m_Mobile.GetMobilesInRange(m_Mobile.RangePerception); + foreach (Mobile trg in eable) { if (trg != m_Mobile && trg.Player && trg.Alive && trg.Hidden && trg.AccessLevel == AccessLevel.Player && m_Mobile.InLOS(trg)) { @@ -2655,6 +2656,7 @@ namespace Server.Mobiles } } } + eable.Free(); } public virtual void Deactivate() diff --git a/Scripts/Mobiles/BaseCreature.cs b/Scripts/Mobiles/BaseCreature.cs index c3d620f42..d03c62c63 100644 --- a/Scripts/Mobiles/BaseCreature.cs +++ b/Scripts/Mobiles/BaseCreature.cs @@ -5429,7 +5429,8 @@ namespace Server.Mobiles { Corpse toRummage = null; - foreach ( Item item in this.GetItemsInRange( 2 ) ) + IPooledEnumerable eable = this.GetItemsInRange(2); + foreach ( Item item in eable ) { if ( item is Corpse && item.Items.Count > 0 ) { @@ -5437,6 +5438,7 @@ namespace Server.Mobiles break; } } + eable.Free(); if ( toRummage == null ) return false; diff --git a/Scripts/Mobiles/PlayerMobile.cs b/Scripts/Mobiles/PlayerMobile.cs index 48189900e..c09bcf05a 100644 --- a/Scripts/Mobiles/PlayerMobile.cs +++ b/Scripts/Mobiles/PlayerMobile.cs @@ -1210,27 +1210,17 @@ namespace Server.Mobiles m_IsStealthing = false; // IsStealthing should be moved to Server.Mobiles } - [CommandProperty( AccessLevel.GameMaster )] - public override bool Hidden + public override void OnHiddenChanged() { - get + RemoveBuff(BuffIcon.Invisibility); //Always remove, default to the hiding icon EXCEPT in the invis spell where it's explicitly set + + if (!Hidden) { - return base.Hidden; + RemoveBuff(BuffIcon.HidingAndOrStealth); } - set + else// if( !InvisibilitySpell.HasTimer( this ) ) { - base.Hidden = value; - - RemoveBuff( BuffIcon.Invisibility ); //Always remove, default to the hiding icon EXCEPT in the invis spell where it's explicitly set - - if( !Hidden ) - { - RemoveBuff( BuffIcon.HidingAndOrStealth ); - } - else// if( !InvisibilitySpell.HasTimer( this ) ) - { - BuffInfo.AddBuff( this, new BuffInfo( BuffIcon.HidingAndOrStealth, 1075655 ) ); //Hidden/Stealthing & You Are Hidden - } + BuffInfo.AddBuff(this, new BuffInfo(BuffIcon.HidingAndOrStealth, 1075655)); //Hidden/Stealthing & You Are Hidden } } diff --git a/Scripts/Regions/GuardedRegion.cs b/Scripts/Regions/GuardedRegion.cs index 53f1b4bf1..331783c3b 100644 --- a/Scripts/Regions/GuardedRegion.cs +++ b/Scripts/Regions/GuardedRegion.cs @@ -176,7 +176,8 @@ namespace Server.Regions { BaseGuard useGuard = null; - foreach ( Mobile m in focus.GetMobilesInRange( 8 ) ) + IPooledEnumerable eable = focus.GetMobilesInRange( 8 ); + foreach ( Mobile m in eable) { if ( m is BaseGuard ) { @@ -190,6 +191,8 @@ namespace Server.Regions } } + eable.Free(); + if ( useGuard == null ) { m_GuardParams[0] = focus; diff --git a/Server/Diagnostics/PacketProfile.cs b/Server/Diagnostics/PacketProfile.cs index 17f76b878..722a4e5d2 100644 --- a/Server/Diagnostics/PacketProfile.cs +++ b/Server/Diagnostics/PacketProfile.cs @@ -20,7 +20,9 @@ using System; using System.Collections.Generic; +using System.Runtime.CompilerServices; using System.Text; +using System.Threading; using System.IO; namespace Server.Diagnostics { @@ -65,11 +67,8 @@ namespace Server.Diagnostics { } } + [MethodImpl(MethodImplOptions.Synchronized)] public static PacketSendProfile Acquire( Type type ) { - if ( !Core.Profiling ) { - return null; - } - PacketSendProfile prof; if ( !_profiles.TryGetValue( type, out prof ) ) { @@ -81,13 +80,8 @@ namespace Server.Diagnostics { private long _created; - public long Created { - get { - return _created; - } - set { - _created = value; - } + public void Increment() { + Interlocked.Increment(ref _created); } public PacketSendProfile( Type type ) @@ -97,7 +91,7 @@ namespace Server.Diagnostics { public override void WriteTo( TextWriter op ) { base.WriteTo( op ); - op.Write( "\t{0,12:N0}", Created ); + op.Write( "\t{0,12:N0}", _created ); } } @@ -110,11 +104,8 @@ namespace Server.Diagnostics { } } + [MethodImpl(MethodImplOptions.Synchronized)] public static PacketReceiveProfile Acquire( int packetId ) { - if ( !Core.Profiling ) { - return null; - } - PacketReceiveProfile prof; if ( !_profiles.TryGetValue( packetId, out prof ) ) { diff --git a/Server/Item.cs b/Server/Item.cs index 59d0e98b6..94b2f3046 100644 --- a/Server/Item.cs +++ b/Server/Item.cs @@ -22,6 +22,10 @@ using System; using System.IO; using System.Collections; using System.Collections.Generic; +#if Framework_4_0 +using System.Linq; +using System.Threading.Tasks; +#endif using Server.Network; using Server.Items; using Server.ContextMenus; @@ -1635,14 +1639,17 @@ namespace Server } } + private object _opll = new object(); + public Packet OPLPacket { get { - if ( m_OPLPacket == null ) - { - m_OPLPacket = new OPLInfo( PropertyList ); - m_OPLPacket.SetStatic(); + lock (_opll) { + if ( m_OPLPacket == null ) { + m_OPLPacket = new OPLInfo( PropertyList ); + m_OPLPacket.SetStatic(); + } } return m_OPLPacket; @@ -1713,6 +1720,10 @@ namespace Server } } + private object _wpl = new object(); + private object _wplsa = new object(); + private object _wplhs = new object(); + public Packet WorldPacket { get @@ -1725,10 +1736,11 @@ namespace Server // - Packet Flags // - Direction - if ( m_WorldPacket == null ) - { - m_WorldPacket = new WorldItem( this ); - m_WorldPacket.SetStatic(); + lock (_wpl) { + if ( m_WorldPacket == null ) { + m_WorldPacket = new WorldItem( this ); + m_WorldPacket.SetStatic(); + } } return m_WorldPacket; @@ -1747,10 +1759,11 @@ namespace Server // - Packet Flags // - Direction - if ( m_WorldPacketSA == null ) - { - m_WorldPacketSA = new WorldItemSA( this ); - m_WorldPacketSA.SetStatic(); + lock (_wplsa) { + if ( m_WorldPacketSA == null ) { + m_WorldPacketSA = new WorldItemSA( this ); + m_WorldPacketSA.SetStatic(); + } } return m_WorldPacketSA; @@ -1769,10 +1782,11 @@ namespace Server // - Packet Flags // - Direction - if ( m_WorldPacketHS == null ) - { - m_WorldPacketHS = new WorldItemHS( this ); - m_WorldPacketHS.SetStatic(); + lock (_wplhs) { + if ( m_WorldPacketHS == null ) { + m_WorldPacketHS = new WorldItemHS( this ); + m_WorldPacketHS.SetStatic(); + } } return m_WorldPacketHS; @@ -3012,6 +3026,8 @@ namespace Server { SetFlag( ImplFlag.InQueue, true ); + if (_processing) + Console.WriteLine(new System.Diagnostics.StackTrace()); m_DeltaQueue.Add( this ); } @@ -3026,6 +3042,8 @@ namespace Server { SetFlag( ImplFlag.InQueue, false ); + if (_processing) + Console.WriteLine(new System.Diagnostics.StackTrace()); m_DeltaQueue.Remove( this ); } } @@ -3124,41 +3142,44 @@ namespace Server if ( openers != null ) { - for ( int i = 0; i < openers.Count; ++i ) + lock (openers) { - Mobile mob = openers[i]; - - int range = GetUpdateRange( mob ); - - if ( mob.Map != map || !mob.InRange( worldLoc, range ) ) + for (int i = 0; i < openers.Count; ++i) { - openers.RemoveAt( i-- ); - } - else - { - if ( mob == rootParent || mob == tradeRecip ) - continue; + Mobile mob = openers[i]; - NetState ns = mob.NetState; + int range = GetUpdateRange(mob); - if ( ns != null ) + if (mob.Map != map || !mob.InRange(worldLoc, range)) { - if ( mob.CanSee( this ) ) - { - if ( ns.ContainerGridLines ) - ns.Send( new ContainerContentUpdate6017( this ) ); - else - ns.Send( new ContainerContentUpdate( this ) ); + openers.RemoveAt(i--); + } + else + { + if (mob == rootParent || mob == tradeRecip) + continue; - if ( ObjectPropertyList.Enabled ) - ns.Send( OPLPacket ); + NetState ns = mob.NetState; + + if (ns != null) + { + if (mob.CanSee(this)) + { + if (ns.ContainerGridLines) + ns.Send(new ContainerContentUpdate6017(this)); + else + ns.Send(new ContainerContentUpdate(this)); + + if (ObjectPropertyList.Enabled) + ns.Send(OPLPacket); + } } } } - } - if ( openers.Count == 0 ) - contParent.Openers = null; + if (openers.Count == 0) + contParent.Openers = null; + } } return; } @@ -3168,10 +3189,15 @@ namespace Server { Packet p = null; Point3D worldLoc = GetWorldLocation(); + object equipUpdateLock = new object(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); +#if Framework_4_0 + Parallel.ForEach( eable.Cast(), state => { +#else foreach ( NetState state in eable ) { +#endif Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) { @@ -3185,8 +3211,11 @@ namespace Server else state.Send( new ContainerContentUpdate( this ) ); } else if ( m_Parent is Mobile ) { - p = new EquipUpdate( this ); - p.Acquire(); + lock (equipUpdateLock) { + p = new EquipUpdate(this); + p.Acquire(); + } + state.Send( p ); } } else { @@ -3199,6 +3228,9 @@ namespace Server } } } +#if Framework_4_0 + ); +#endif if ( p != null ) Packet.Release( p ); @@ -3212,11 +3244,15 @@ namespace Server { Packet p = null; Point3D worldLoc = GetWorldLocation(); + object equipPacketLock = new object(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); - foreach ( NetState state in eable ) - { +#if Framework_4_0 + Parallel.ForEach( eable.Cast(), state => { +#else + foreach ( NetState state in eable ) { +#endif Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) @@ -3224,8 +3260,9 @@ namespace Server //if ( sendOPLUpdate ) // state.Send( RemovePacket ); - if ( p == null ) - p = Packet.Acquire( new EquipUpdate( this ) ); + lock (equipPacketLock) + if ( p == null ) + p = Packet.Acquire( new EquipUpdate( this ) ); state.Send( p ); @@ -3233,6 +3270,9 @@ namespace Server state.Send( OPLPacket ); } } +#if Framework_4_0 + ); +#endif Packet.Release( p ); @@ -3246,33 +3286,45 @@ namespace Server Point3D worldLoc = GetWorldLocation(); IPooledEnumerable eable = map.GetClientsInRange( worldLoc, GetMaxUpdateRange() ); - foreach ( NetState state in eable ) - { +#if Framework_4_0 + Parallel.ForEach( eable.Cast(), state => { +#else + foreach ( NetState state in eable ) { +#endif Mobile m = state.Mobile; if ( m.CanSee( this ) && m.InRange( worldLoc, GetUpdateRange( m ) ) ) state.Send( OPLPacket ); } +#if Framework_4_0 + ); +#endif eable.Free(); } } } + private static bool _processing = false; + public static void ProcessDeltaQueue() { +#if Framework_4_0 + _processing = true; + Parallel.ForEach( m_DeltaQueue, i => i.ProcessDelta() ); + m_DeltaQueue.Clear(); + _processing = false; +#else int count = m_DeltaQueue.Count; - for ( int i = 0; i < m_DeltaQueue.Count; ++i ) - { + for (int i = 0; i < m_DeltaQueue.Count; ++i) { m_DeltaQueue[i].ProcessDelta(); - if ( i >= count ) + if (i >= count) break; } - - if ( m_DeltaQueue.Count > 0 ) - m_DeltaQueue.Clear(); + m_DeltaQueue.Clear(); +#endif } public virtual void OnDelete() diff --git a/Server/Map.cs b/Server/Map.cs index c68f42a61..2c0dc0277 100644 --- a/Server/Map.cs +++ b/Server/Map.cs @@ -1098,30 +1098,9 @@ namespace Server { private IPooledEnumerator m_Enumerator; - private static Queue m_InstancePool = new Queue(); - private static int m_Depth = 0; - public static PooledEnumerable Instantiate( IPooledEnumerator etor ) { - ++m_Depth; - - if ( m_Depth >= 5 ) - Console.WriteLine( "Warning: Make sure to call .Free() on pooled enumerables." ); - - PooledEnumerable e; - - if ( m_InstancePool.Count > 0 ) - { - e = m_InstancePool.Dequeue(); - e.m_Enumerator = etor; - } - else - { - e = new PooledEnumerable( etor ); - } - - etor.Enumerable = e; - + PooledEnumerable e = new PooledEnumerable( etor ); return e; } @@ -1133,7 +1112,7 @@ namespace Server public IEnumerator GetEnumerator() { if ( m_Enumerator == null ) - throw new ObjectDisposedException( "PooledEnumerable", "GetEnumerator() called after Free()" ); + throw new ObjectDisposedException("PooledEnumerable", "GetEnumerator() called after Free()"); return m_Enumerator; } @@ -1142,12 +1121,8 @@ namespace Server { if ( m_Enumerator != null ) { - m_InstancePool.Enqueue( this ); - m_Enumerator.Free(); m_Enumerator = null; - - --m_Depth; } } @@ -1182,27 +1157,10 @@ namespace Server private SectorEnumeratorType m_Type; private object m_Current; - private static Queue m_InstancePool = new Queue(); - - public static TypedEnumerator Instantiate( Map map, Rectangle2D bounds, SectorEnumeratorType type ) - { - TypedEnumerator e; - - if ( m_InstancePool.Count > 0 ) - { - e = m_InstancePool.Dequeue(); - - e.m_Map = map; - e.m_Bounds = bounds; - e.m_Type = type; - - e.Reset(); - } - else - { - e = new TypedEnumerator( map, bounds, type ); - } + public static TypedEnumerator Instantiate( Map map, Rectangle2D bounds, SectorEnumeratorType type ) { + TypedEnumerator e = new TypedEnumerator(map, bounds, type); + e.Reset(); return e; } @@ -1211,18 +1169,13 @@ namespace Server if ( m_Map == null ) return; - m_InstancePool.Enqueue( this ); - - m_Map = null; - if ( m_Enumerator != null ) { m_Enumerator.Free(); m_Enumerator = null; } - if ( m_Enumerable != null ) - m_Enumerable.Free(); + m_Map = null; } public TypedEnumerator( Map map, Rectangle2D bounds, SectorEnumeratorType type ) @@ -1230,22 +1183,22 @@ namespace Server m_Map = map; m_Bounds = bounds; m_Type = type; - - Reset(); } - public object Current - { - get - { - return m_Current; - } + public object Current { + get { return m_Current; } } public bool MoveNext() { while ( true ) { + if (m_Enumerator == null) + { + Console.WriteLine("hmm m_Enumerator null??"); + return false; + } + if ( m_Enumerator.MoveNext() ) { object o; @@ -1256,6 +1209,7 @@ namespace Server } catch { + Console.WriteLine("typed Enum current null"); continue; } @@ -1293,10 +1247,6 @@ namespace Server else { m_Current = null; - - m_Enumerator.Free(); - m_Enumerator = null; - return false; } } @@ -1305,11 +1255,7 @@ namespace Server public void Reset() { m_Current = null; - - if ( m_Enumerator != null ) - m_Enumerator.Free(); - - m_Enumerator = SectorEnumerator.Instantiate( m_Map, m_Bounds, m_Type );//new SectorEnumerator( m_Map, m_Origin, m_Type, m_Range ); + m_Enumerator = SectorEnumerator.Instantiate( m_Map, m_Bounds, m_Type ); } public void Dispose() @@ -1333,26 +1279,11 @@ namespace Server private object m_Current; private int m_Index; - private static Queue m_InstancePool = new Queue(); - public static MultiTileEnumerator Instantiate( Sector sector, Point2D loc ) { - MultiTileEnumerator e; - - if ( m_InstancePool.Count > 0 ) - { - e = m_InstancePool.Dequeue(); - - e.m_List = sector.Multis; - e.m_Location = loc; - - e.Reset(); - } - else - { - e = new MultiTileEnumerator( sector, loc ); - } + MultiTileEnumerator e = new MultiTileEnumerator( sector, loc ); + e.Reset(); return e; } @@ -1360,14 +1291,10 @@ namespace Server { m_List = sector.Multis; m_Location = loc; - - Reset(); } - public object Current - { - get - { + public object Current { + get { return m_Current; } } @@ -1415,12 +1342,7 @@ namespace Server if ( m_List == null ) return; - m_InstancePool.Enqueue( this ); - m_List = null; - - if ( m_Enumerable != null ) - m_Enumerable.Free(); } public void Reset() @@ -1451,26 +1373,11 @@ namespace Server private int m_Stage; // 0 = items, 1 = mobiles private object m_Current; - private static Queue m_InstancePool = new Queue(); - public static ObjectEnumerator Instantiate( Map map, Rectangle2D bounds ) { - ObjectEnumerator e; - - if ( m_InstancePool.Count > 0 ) - { - e = m_InstancePool.Dequeue(); - - e.m_Map = map; - e.m_Bounds = bounds; - - e.Reset(); - } - else - { - e = new ObjectEnumerator( map, bounds ); - } + ObjectEnumerator e = new ObjectEnumerator(map, bounds); + e.Reset(); return e; } @@ -1479,8 +1386,6 @@ namespace Server if ( m_Map == null ) return; - m_InstancePool.Enqueue( this ); - m_Map = null; if ( m_Enumerator != null ) @@ -1488,26 +1393,15 @@ namespace Server m_Enumerator.Free(); m_Enumerator = null; } - - if ( m_Enumerable != null ) - m_Enumerable.Free(); } private ObjectEnumerator( Map map, Rectangle2D bounds ) { m_Map = map; m_Bounds = bounds; - - Reset(); } - public object Current - { - get - { - return m_Current; - } - } + public object Current { get { return m_Current; } } public bool MoveNext() { @@ -1523,6 +1417,7 @@ namespace Server } catch { + Console.WriteLine("OBJ Enum current null"); continue; } @@ -1608,25 +1503,10 @@ namespace Server private static Queue m_InstancePool = new Queue(); - public static SectorEnumerator Instantiate( Map map, Rectangle2D bounds, SectorEnumeratorType type ) - { - SectorEnumerator e; - - if ( m_InstancePool.Count > 0 ) - { - e = m_InstancePool.Dequeue(); - - e.m_Map = map; - e.m_Bounds = bounds; - e.m_Type = type; - - e.Reset(); - } - else - { - e = new SectorEnumerator( map, bounds, type ); - } + public static SectorEnumerator Instantiate( Map map, Rectangle2D bounds, SectorEnumeratorType type ) { + SectorEnumerator e = new SectorEnumerator(map, bounds, type); + e.Reset(); return e; } @@ -1635,12 +1515,7 @@ namespace Server if ( m_Map == null ) return; - m_InstancePool.Enqueue( this ); - - m_Map = null; - - if ( m_Enumerable != null ) - m_Enumerable.Free(); + //m_Map = null; } private SectorEnumerator( Map map, Rectangle2D bounds, SectorEnumeratorType type ) @@ -1648,8 +1523,6 @@ namespace Server m_Map = map; m_Bounds = bounds; m_Type = type; - - Reset(); } private IList GetListForSector( Sector sector ) @@ -1667,32 +1540,8 @@ namespace Server } } - public object Current - { - get - { - return m_CurrentList[m_CurrentIndex]; - /*try - { - return m_CurrentList[m_CurrentIndex]; - } - catch - { - Console.WriteLine( "Warning: Object removed during enumeration. May not be recoverable" ); - - m_CurrentIndex = -1; - m_CurrentList = GetListForSector( m_Map.InternalGetSector( m_xSector, m_ySector ) ); - - if ( MoveNext() ) - { - return Current; - } - else - { - throw new Exception( "Object disposed during enumeration. Was not recoverable." ); - } - }*/ - } + public object Current { + get { return m_CurrentList[m_CurrentIndex]; } } public bool MoveNext() @@ -1701,6 +1550,9 @@ namespace Server { ++m_CurrentIndex; + if (m_CurrentList == null) + return false; // So much fail with PooledEnumerables >< + if ( m_CurrentIndex == m_CurrentList.Count ) { ++m_ySector; diff --git a/Server/Mobile.cs b/Server/Mobile.cs index a0d5275ce..48b1b924c 100644 --- a/Server/Mobile.cs +++ b/Server/Mobile.cs @@ -23,6 +23,10 @@ using System.Collections; using System.Collections.Generic; using System.IO; using System.Text; +#if Framework_4_0 +using System.Linq; +using System.Threading.Tasks; +#endif using Server; using Server.Accounting; using Server.Commands; @@ -4913,7 +4917,7 @@ namespace Server } } - //eable.Free(); + eable.Free(); object mutateContext = null; string mutatedText = text; @@ -7988,7 +7992,7 @@ namespace Server } [CommandProperty( AccessLevel.GameMaster )] - public virtual bool Hidden + public bool Hidden { get { @@ -7998,49 +8002,54 @@ namespace Server { if( m_Hidden != value ) { - m_AllowedStealthSteps = 0; - m_Hidden = value; //Delta( MobileDelta.Flags ); - if( m_Map != null ) + OnHiddenChanged(); + } + } + } + + public virtual void OnHiddenChanged() + { + m_AllowedStealthSteps = 0; + + if (m_Map != null) + { + Packet p = null; + + IPooledEnumerable eable = m_Map.GetClientsInRange(m_Location); + + foreach (NetState state in eable) + { + if (!state.Mobile.CanSee(this)) { - Packet p = null; + if (p == null) + p = this.RemovePacket; - IPooledEnumerable eable = m_Map.GetClientsInRange( m_Location ); + state.Send(p); + } + else + { + if (state.StygianAbyss) + state.Send(new MobileIncoming(state.Mobile, this)); + else + state.Send(new MobileIncomingOld(state.Mobile, this)); - foreach( NetState state in eable ) + if (IsDeadBondedPet) + state.Send(new BondedStatus(0, m_Serial, 1)); + + if (ObjectPropertyList.Enabled) { - if( !state.Mobile.CanSee( this ) ) - { - if( p == null ) - p = this.RemovePacket; + state.Send(OPLPacket); - state.Send( p ); - } - else - { - if ( state.StygianAbyss ) - state.Send( new MobileIncoming( state.Mobile, this ) ); - else - state.Send( new MobileIncomingOld( state.Mobile, this ) ); - - if( IsDeadBondedPet ) - state.Send( new BondedStatus( 0, m_Serial, 1 ) ); - - if( ObjectPropertyList.Enabled ) - { - state.Send( OPLPacket ); - - //foreach ( Item item in m_Items ) - // state.Send( item.OPLPacket ); - } - } + //foreach ( Item item in m_Items ) + // state.Send( item.OPLPacket ); } - - eable.Free(); } } + + eable.Free(); } } @@ -9956,6 +9965,8 @@ namespace Server { m_InDeltaQueue = true; + if (_processing) + Console.WriteLine(new System.Diagnostics.StackTrace()); m_DeltaQueue.Enqueue( this ); } @@ -10121,7 +10132,9 @@ namespace Server sendPublicStats = true; } - if( (delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | MobileDelta.Followers | MobileDelta.TithingPoints | MobileDelta.Race)) != 0 ) + if( (delta & (MobileDelta.WeaponDamage | MobileDelta.Resistances | MobileDelta.Stat | + MobileDelta.Weight | MobileDelta.Gold | MobileDelta.Armor | MobileDelta.StatCap | + MobileDelta.Followers | MobileDelta.TithingPoints | MobileDelta.Race)) != 0 ) { sendPrivateStats = true; } @@ -10142,6 +10155,9 @@ namespace Server sendFacialHair = true; } +#if Framework_4_0 + Packet[][] cache = new Packet[2][] { new Packet[8], new Packet[8] }; +#else Packet[][] cache = m_MovingPacketCache; if( sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow ) @@ -10150,6 +10166,7 @@ namespace Server for( int j = 0; j < cache[i].Length; ++j ) Packet.Release( ref cache[i][j] ); } +#endif NetState ourState = m.m_NetState; @@ -10252,22 +10269,42 @@ namespace Server { Mobile beholder; - IPooledEnumerable eable = m.Map.GetClientsInRange( m.m_Location ); - Packet hitsPacket = null; - Packet statPacketTrue = null, statPacketFalse = null; + Packet statPacketTrue = null; + Packet statPacketFalse = null; Packet deadPacket = null; - Packet hairPacket = null, facialhairPacket = null; - Packet hbpPacket = null, hbyPacket = null; + Packet hairPacket = null; + Packet facialhairPacket = null; + Packet hbpPacket = null; + Packet hbyPacket = null; - foreach( NetState state in eable ) - { + // 9 Separate Locks.. Feels Dirty + object hitsPacketLock = new object(); + object statPacketTrueLock = new object(); + object statPacketFalseLock = new object(); + object deadPacketLock = new object(); + object hairPacketLock = new object(); + object facialhairPacketLock = new object(); + object hbpPacketLock = new object(); + object hbyPacketLock = new object(); + object cacheSync = new object(); + + Packet removePacket = RemovePacket; + Packet oplPacket = OPLPacket; + + IPooledEnumerable eable = m.Map.GetClientsInRange(m.m_Location); + +#if Framework_4_0 + Parallel.ForEach( eable.Cast(), state => { +#else + foreach ( NetState state in eable ) { +#endif beholder = state.Mobile; if( beholder != m && beholder.CanSee( m ) ) { if( sendRemove ) - state.Send( m.RemovePacket ); + state.Send(removePacket); if( sendIncoming ) { @@ -10279,8 +10316,11 @@ namespace Server if( m.IsDeadBondedPet ) { - if( deadPacket == null ) - deadPacket = Packet.Acquire( new BondedStatus( 0, m.m_Serial, 1 ) ); + lock (deadPacketLock) + { + if (deadPacket == null) + deadPacket = Packet.Acquire(new BondedStatus(0, m.m_Serial, 1)); + } state.Send( deadPacket ); } @@ -10291,24 +10331,36 @@ namespace Server { int noto = Notoriety.Compute( beholder, m ); - Packet p = cache[0][noto]; + Packet p; - if( p == null ) - cache[0][noto] = p = Packet.Acquire( new MobileMoving( m, noto ) ); + lock (cacheSync) + { + p = cache[0][noto]; + + if (p == null) + cache[0][noto] = p = Packet.Acquire(new MobileMoving(m, noto)); + } state.Send( p ); } if ( sendHealthbarPoison ) { - if ( hbpPacket == null ) - hbpPacket = Packet.Acquire( new HealthbarPoison( m ) ); - + lock (hbpPacketLock) + { + if (hbpPacket == null) + hbpPacket = Packet.Acquire(new HealthbarPoison(m)); + } + state.Send( hbpPacket ); } if ( sendHealthbarYellow ) { - if ( hbyPacket == null ) - hbyPacket = Packet.Acquire( new HealthbarYellow( m ) ); + lock (hbyPacketLock) + { + if (hbyPacket == null) + hbyPacket = Packet.Acquire(new HealthbarYellow(m)); + } + state.Send( hbyPacket ); } } else { @@ -10316,10 +10368,15 @@ namespace Server { int noto = Notoriety.Compute( beholder, m ); - Packet p = cache[1][noto]; + Packet p; - if( p == null ) - cache[1][noto] = p = Packet.Acquire( new MobileMovingOld( m, noto ) ); + lock (cacheSync) + { + p = cache[1][noto]; + + if (p == null) + cache[1][noto] = p = Packet.Acquire(new MobileMovingOld(m, noto)); + } state.Send( p ); } @@ -10329,35 +10386,45 @@ namespace Server { if( m.CanBeRenamedBy( beholder ) ) { - if( statPacketTrue == null ) - statPacketTrue = Packet.Acquire( new MobileStatusCompact( true, m ) ); + lock (statPacketTrueLock) + { + if (statPacketTrue == null) + statPacketTrue = Packet.Acquire(new MobileStatusCompact(true, m)); + } state.Send( statPacketTrue ); } else { - if( statPacketFalse == null ) - statPacketFalse = Packet.Acquire( new MobileStatusCompact( false, m ) ); + lock (statPacketFalseLock) + { + if (statPacketFalse == null) + statPacketFalse = Packet.Acquire(new MobileStatusCompact(false, m)); + } state.Send( statPacketFalse ); } } else if( sendHits ) { - if( hitsPacket == null ) - hitsPacket = Packet.Acquire( new MobileHitsN( m ) ); + lock (hitsPacketLock) + { + if (hitsPacket == null) + hitsPacket = Packet.Acquire(new MobileHitsN(m)); + } state.Send( hitsPacket ); } if( sendHair ) { - if( hairPacket == null ) - { - if( removeHair ) - hairPacket = Packet.Acquire( new RemoveHair( m ) ); - else - hairPacket = Packet.Acquire( new HairEquipUpdate( m ) ); + lock (hairPacketLock) { + if (hairPacket == null) { + if (removeHair) + hairPacket = Packet.Acquire(new RemoveHair(m)); + else + hairPacket = Packet.Acquire(new HairEquipUpdate(m)); + } } state.Send( hairPacket ); @@ -10365,21 +10432,25 @@ namespace Server if( sendFacialHair ) { - if( facialhairPacket == null ) - { - if( removeFacialHair ) - facialhairPacket = Packet.Acquire( new RemoveFacialHair( m ) ); - else - facialhairPacket = Packet.Acquire( new FacialHairEquipUpdate( m ) ); + lock (facialhairPacketLock) { + if (facialhairPacket == null) { + if (removeFacialHair) + facialhairPacket = Packet.Acquire(new RemoveFacialHair(m)); + else + facialhairPacket = Packet.Acquire(new FacialHairEquipUpdate(m)); + } } state.Send( facialhairPacket ); } if( sendOPLUpdate ) - state.Send( OPLPacket ); + state.Send(oplPacket); } } +#if Framework_4_0 + ); +#endif Packet.Release( hitsPacket ); Packet.Release( statPacketTrue ); @@ -10396,18 +10467,27 @@ namespace Server if( sendMoving || sendNonlocalMoving || sendHealthbarPoison || sendHealthbarYellow ) { for( int i = 0; i < cache.Length; ++i ) - for( int j = 0; j < cache.Length; ++j ) - Packet.Release( ref cache[i][j] ); + for( int j = 0; j < cache[i].Length; ++j ) + Packet.Release(ref cache[i][j]); } } + public static bool _processing = false; + public static void ProcessDeltaQueue() { +#if Framework_4_0 + _processing = true; + Parallel.ForEach( m_DeltaQueue, m => m.ProcessDelta() ); + m_DeltaQueue.Clear(); + _processing = false; +#else int count = m_DeltaQueue.Count; int index = 0; while( m_DeltaQueue.Count > 0 && index++ < count ) m_DeltaQueue.Dequeue().ProcessDelta(); +#endif } [CommandProperty( AccessLevel.Counselor, AccessLevel.GameMaster )] diff --git a/Server/Network/Compression.cs b/Server/Network/Compression.cs index 6a096271c..90c5e2478 100644 --- a/Server/Network/Compression.cs +++ b/Server/Network/Compression.cs @@ -83,92 +83,104 @@ namespace Server.Network { // If our input exceeds this length, we may potentially overflow the buffer private const int PossibleOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MaximalCodeLength; - private static object _syncRoot = new object(); - - private static byte[] _outputBuffer = new byte[BufferSize]; - - [Obsolete( "Use Compress( byte[], int, int, ref int ) instead.", false )] - public static void Compress( byte[] input, int length, out byte[] output, out int outputLength ) { - outputLength = 0; - output = Compress( input, 0, length, ref outputLength ); - } - - public unsafe static byte[] Compress( byte[] input, int offset, int count, ref int length ) { - if ( input == null ) { - throw new ArgumentNullException( "input" ); - } else if ( offset < 0 || offset >= input.Length ) { - throw new ArgumentOutOfRangeException( "offset" ); - } else if ( count < 0 || count > input.Length ) { - throw new ArgumentOutOfRangeException( "count" ); - } else if ( ( input.Length - offset ) < count ) { + public unsafe static void Compress(byte[] input, int offset, int count, byte[] output, ref int length) + { + if (input == null) + { + throw new ArgumentNullException("input"); + } + else if (offset < 0 || offset >= input.Length) + { + throw new ArgumentOutOfRangeException("offset"); + } + else if (count < 0 || count > input.Length) + { + throw new ArgumentOutOfRangeException("count"); + } + else if ((input.Length - offset) < count) + { throw new ArgumentException(); } length = 0; - if ( count > DefiniteOverflow ) { - return null; + if (count > DefiniteOverflow) + { + return; } - lock ( _syncRoot ) { - int bitCount = 0; - int bitValue = 0; + int bitCount = 0; + int bitValue = 0; - fixed ( int* pTable = _huffmanTable ) { - int* pEntry; + fixed (int* pTable = _huffmanTable) + { + int* pEntry; - fixed ( byte* pInputBuffer = input ) { - byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count; + fixed (byte* pInputBuffer = input) + { + byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count; - fixed ( byte* pOutputBuffer = _outputBuffer ) { - byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize; + fixed (byte* pOutputBuffer = output) + { + byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize; - while ( pInput < pInputEnd ) { - pEntry = &pTable[*pInput++ << 1]; - - bitCount += pEntry[CountIndex]; - - bitValue <<= pEntry[CountIndex]; - bitValue |= pEntry[ValueIndex]; - - while ( bitCount >= 8 ) { - bitCount -= 8; - - if ( pOutput < pOutputEnd ) { - *pOutput++ = ( byte ) ( bitValue >> bitCount ); - } else { - return null; - } - } - } - - // terminal code - pEntry = &pTable[0x200]; + while (pInput < pInputEnd) + { + pEntry = &pTable[*pInput++ << 1]; bitCount += pEntry[CountIndex]; bitValue <<= pEntry[CountIndex]; bitValue |= pEntry[ValueIndex]; - // align on byte boundary - if ( ( bitCount & 7 ) != 0 ) { - bitValue <<= ( 8 - ( bitCount & 7 ) ); - bitCount += ( 8 - ( bitCount & 7 ) ); - } - - while ( bitCount >= 8 ) { + while (bitCount >= 8) + { bitCount -= 8; - if ( pOutput < pOutputEnd ) { - *pOutput++ = ( byte ) ( bitValue >> bitCount ); - } else { - return null; + if (pOutput < pOutputEnd) + { + *pOutput++ = (byte)(bitValue >> bitCount); + } + else + { + length = 0; + return; } } - - length = ( int ) ( pOutput - pOutputBuffer ); - return _outputBuffer; } + + // terminal code + pEntry = &pTable[0x200]; + + bitCount += pEntry[CountIndex]; + + bitValue <<= pEntry[CountIndex]; + bitValue |= pEntry[ValueIndex]; + + // align on byte boundary + if ((bitCount & 7) != 0) + { + bitValue <<= (8 - (bitCount & 7)); + bitCount += (8 - (bitCount & 7)); + } + + while (bitCount >= 8) + { + bitCount -= 8; + + if (pOutput < pOutputEnd) + { + *pOutput++ = (byte)(bitValue >> bitCount); + } + else + { + length = 0; + return; + } + } + + length = (int)(pOutput - pOutputBuffer); + return; } } } diff --git a/Server/Network/MessagePump.cs b/Server/Network/MessagePump.cs index 8a3b7e6f3..7a0743131 100644 --- a/Server/Network/MessagePump.cs +++ b/Server/Network/MessagePump.cs @@ -236,7 +236,9 @@ namespace Server.Network return; } - PacketReceiveProfile prof = PacketReceiveProfile.Acquire( packetID ); + PacketReceiveProfile prof = null; + + if (Core.Profiling) prof = PacketReceiveProfile.Acquire( packetID ); if ( prof != null ) { prof.Start(); diff --git a/Server/Network/NetState.cs b/Server/Network/NetState.cs index 78e5a4615..bb67c88ea 100644 --- a/Server/Network/NetState.cs +++ b/Server/Network/NetState.cs @@ -19,12 +19,14 @@ ***************************************************************************/ using System; -using System.Collections; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Sockets; using System.Threading; +#if Framework_4_0 +using System.Threading.Tasks; +#endif using Server; using Server.Accounting; using Server.Network; @@ -588,14 +590,15 @@ namespace Server.Network { } } + private bool _sending; + private object _sendL = new object(); + public virtual void Send( Packet p ) { if ( m_Socket == null || m_BlockAllPackets ) { p.OnSend(); return; } - PacketSendProfile prof = PacketSendProfile.Acquire( p.GetType() ); - int length; byte[] buffer = p.Compile( m_CompressionEnabled, out length ); @@ -605,6 +608,10 @@ namespace Server.Network { return; } + PacketSendProfile prof = null; + + if (Core.Profiling) prof = PacketSendProfile.Acquire(p.GetType()); + if ( prof != null ) { prof.Start(); } @@ -616,22 +623,27 @@ namespace Server.Network { try { SendQueue.Gram gram; - lock ( m_SendQueue ) { - gram = m_SendQueue.Enqueue( buffer, length ); - } + lock (_sendL) { + lock (m_SendQueue) + gram = m_SendQueue.Enqueue(buffer, length); - if ( gram != null ) { + if (gram != null) { #if NewAsyncSockets - m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length ); - Send_Start(); + m_SendEventArgs.SetBuffer( gram.Buffer, 0, gram.Length ); + Send_Start(); #else - try { - m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket ); - } catch ( Exception ex ) { - TraceException( ex ); - Dispose( false ); - } + try { + if (!_sending) { + _sending = true; + m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket); + } + } + catch (Exception ex) { + TraceException(ex); + Dispose(false); + } #endif + } } } catch ( CapacityExceededException ) { Console.WriteLine( "Client: {0}: Too much data pending, disconnecting...", this ); @@ -814,13 +826,15 @@ namespace Server.Network { } public bool Flush() { - if ( m_Socket == null || !m_SendQueue.IsFlushReady ) { - return false; - } + if ( m_Socket == null ) + return false; SendQueue.Gram gram; lock ( m_SendQueue ) { + if (!m_SendQueue.IsFlushReady) + return false; + gram = m_SendQueue.CheckFlushReady(); } @@ -914,23 +928,26 @@ namespace Server.Network { m_NextCheckActivity = Core.TickCount + 90000; - if ( m_CoalesceSleep >= 0 ) { - Thread.Sleep( m_CoalesceSleep ); + if (m_CoalesceSleep >= 0) { + Thread.Sleep(m_CoalesceSleep); } SendQueue.Gram gram; - lock ( m_SendQueue ) { + lock (m_SendQueue) { gram = m_SendQueue.Dequeue(); } - if ( gram != null ) { + if (gram != null) { try { - s.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s ); - } catch ( Exception ex ) { - TraceException( ex ); - Dispose( false ); + s.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, s); + } catch (Exception ex) { + TraceException(ex); + Dispose(false); } + } else { + lock (_sendL) + _sending = false; } } catch ( Exception ){ Dispose( false ); @@ -974,23 +991,31 @@ namespace Server.Network { } public bool Flush() { - if ( m_Socket == null || !m_SendQueue.IsFlushReady ) { + if (m_Socket == null) return false; - } - SendQueue.Gram gram; + lock (_sendL) { + if (_sending) + return false; - lock ( m_SendQueue ) { - gram = m_SendQueue.CheckFlushReady(); - } + SendQueue.Gram gram; - if ( gram != null ) { - try { - m_Socket.BeginSend( gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket ); - return true; - } catch ( Exception ex ) { - TraceException( ex ); - Dispose( false ); + lock (m_SendQueue) { + if (!m_SendQueue.IsFlushReady) + return false; + + gram = m_SendQueue.CheckFlushReady(); + } + + if (gram != null) { + try { + _sending = true; + m_Socket.BeginSend(gram.Buffer, 0, gram.Length, SocketFlags.None, m_OnSend, m_Socket); + return true; + } catch (Exception ex) { + TraceException(ex); + Dispose(false); + } } } @@ -1007,11 +1032,13 @@ namespace Server.Network { } public static void FlushAll() { +#if Framework_4_0 + Parallel.ForEach( m_Instances, ns => ns.Flush() ); +#else for ( int i = 0; i < m_Instances.Count; ++i ) { - NetState ns = m_Instances[i]; - - ns.Flush(); + m_Instances[i].Flush(); } +#endif } private static int m_CoalesceSleep = -1; @@ -1109,10 +1136,11 @@ namespace Server.Network { m_Running = false; - m_Disposed.Enqueue( this ); + lock (m_Disposed) + m_Disposed.Enqueue( this ); - if ( /*!flush &&*/ !m_SendQueue.IsEmpty ) { - lock ( m_SendQueue ) + lock (m_SendQueue) + if ( /*!flush &&*/ !m_SendQueue.IsEmpty ) { m_SendQueue.Clear(); } } @@ -1131,37 +1159,38 @@ namespace Server.Network { } } - private static Queue m_Disposed = Queue.Synchronized( new Queue() ); + private static Queue m_Disposed = new Queue(); public static void ProcessDisposedQueue() { - int breakout = 0; + lock (m_Disposed) { + int breakout = 0; - while ( breakout < 200 && m_Disposed.Count > 0 ) { - ++breakout; + while ( breakout < 200 && m_Disposed.Count > 0 ) { + ++breakout; + NetState ns = m_Disposed.Dequeue(); - NetState ns = ( NetState ) m_Disposed.Dequeue(); + Mobile m = ns.m_Mobile; + IAccount a = ns.m_Account; - Mobile m = ns.m_Mobile; - IAccount a = ns.m_Account; + if ( m != null ) { + m.NetState = null; + ns.m_Mobile = null; + } - if ( m != null ) { - m.NetState = null; - ns.m_Mobile = null; - } + ns.m_Gumps.Clear(); + ns.m_Menus.Clear(); + ns.m_HuePickers.Clear(); + ns.m_Account = null; + ns.m_ServerInfo = null; + ns.m_CityInfo = null; - ns.m_Gumps.Clear(); - ns.m_Menus.Clear(); - ns.m_HuePickers.Clear(); - ns.m_Account = null; - ns.m_ServerInfo = null; - ns.m_CityInfo = null; + m_Instances.Remove( ns ); - m_Instances.Remove( ns ); - - if ( a != null ) { - ns.WriteConsole( "Disconnected. [{0} Online] [{1}]", m_Instances.Count, a ); - } else { - ns.WriteConsole( "Disconnected. [{0} Online]", m_Instances.Count ); + if ( a != null ) { + ns.WriteConsole( "Disconnected. [{0} Online] [{1}]", m_Instances.Count, a ); + } else { + ns.WriteConsole( "Disconnected. [{0} Online]", m_Instances.Count ); + } } } } diff --git a/Server/Network/PacketWriter.cs b/Server/Network/PacketWriter.cs index b0d1fd35c..e730ff2cd 100644 --- a/Server/Network/PacketWriter.cs +++ b/Server/Network/PacketWriter.cs @@ -97,7 +97,7 @@ namespace Server.Network /// /// Internal format buffer. /// - private static byte[] m_Buffer = new byte[4]; + private byte[] m_Buffer = new byte[4]; /// /// Instantiates a new PacketWriter instance with the default capacity of 4 bytes. diff --git a/Server/Network/Packets.cs b/Server/Network/Packets.cs index 34077c641..2b588c589 100644 --- a/Server/Network/Packets.cs +++ b/Server/Network/Packets.cs @@ -2475,7 +2475,8 @@ namespace Server.Network PacketWriter.ReleaseInstance( m_Strings ); } - private static byte[] m_PackBuffer; + private const int GumpBufferSize = 0x4000; + private static BufferPool m_PackBuffers = new BufferPool("Gump", 4, GumpBufferSize); private void WritePacked( PacketWriter src ) { @@ -2493,8 +2494,15 @@ namespace Server.Network wantLength += 4095; wantLength &= ~4095; - if ( m_PackBuffer == null || m_PackBuffer.Length < wantLength ) + byte[] m_PackBuffer; + lock (m_PackBuffers) + m_PackBuffer = m_PackBuffers.AcquireBuffer(); + + if (m_PackBuffer.Length < wantLength) + { + Console.WriteLine("Notice: DisplayGumpPacked creating new {0} byte buffer", wantLength); m_PackBuffer = new byte[wantLength]; + } int packLength = m_PackBuffer.Length; @@ -2503,6 +2511,9 @@ namespace Server.Network m_Stream.Write( (int) ( 4 + packLength ) ); m_Stream.Write( (int) length ); m_Stream.Write( m_PackBuffer, 0, packLength ); + + lock (m_PackBuffers) + m_PackBuffers.ReleaseBuffer(m_PackBuffer); } } @@ -2517,6 +2528,8 @@ namespace Server.Network public DisplayGumpFast( Gump g ) : base( 0xB0 ) { + m_Buffer[0] = (byte)' '; + EnsureCapacity( 4096 ); m_Stream.Write( (int) g.Serial ); @@ -2532,12 +2545,7 @@ namespace Server.Network private static byte[] m_BeginTextSeparator = Gump.StringToBuffer( " @" ); private static byte[] m_EndTextSeparator = Gump.StringToBuffer( "@" ); - private static byte[] m_Buffer = new byte[48]; - - static DisplayGumpFast() - { - m_Buffer[0] = (byte)' '; - } + private byte[] m_Buffer = new byte[48]; public void AppendLayout( bool val ) { @@ -4378,10 +4386,9 @@ namespace Server.Network { m_PacketID = packetID; - PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); - - if ( prof != null ) { - prof.Created++; + if (Core.Profiling) { + PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); + prof.Increment(); } } @@ -4400,10 +4407,9 @@ namespace Server.Network m_Stream = PacketWriter.CreateInstance( length );// new PacketWriter( length ); m_Stream.Write( ( byte ) packetID ); - PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); - - if ( prof != null ) { - prof.Created++; + if (Core.Profiling) { + PacketSendProfile prof = PacketSendProfile.Acquire( GetType() ); + prof.Increment(); } } @@ -4415,6 +4421,9 @@ namespace Server.Network } } + private const int CompressorBufferSize = 0x10000; + private static BufferPool m_CompressorBuffers = new BufferPool("Compressor", 4, CompressorBufferSize); + private const int BufferSize = 4096; private static BufferPool m_Buffers = new BufferPool( "Compressed", 16, BufferSize ); @@ -4490,8 +4499,10 @@ namespace Server.Network { Core.Set(); - if ( (m_State & (State.Acquired | State.Static)) == 0 ) - Free(); + lock (this) { + if ((m_State & (State.Acquired | State.Static)) == 0) + Free(); + } } private void Free() @@ -4499,8 +4510,8 @@ namespace Server.Network if ( m_CompiledBuffer == null ) return; - if ( (m_State & State.Buffered) != 0 ) - m_Buffers.ReleaseBuffer( m_CompiledBuffer ); + if ((m_State & State.Buffered) != 0) + m_Buffers.ReleaseBuffer(m_CompiledBuffer); m_State &= ~(State.Static | State.Acquired | State.Buffered); @@ -4509,7 +4520,7 @@ namespace Server.Network public void Release() { - if ( (m_State & State.Acquired) != 0 ) + if ((m_State & State.Acquired) != 0) Free(); } @@ -4518,43 +4529,46 @@ namespace Server.Network public byte[] Compile( bool compress, out int length ) { - if ( m_CompiledBuffer == null ) + lock (this) { - if ( (m_State & State.Accessed) == 0 ) + if (m_CompiledBuffer == null) { - m_State |= State.Accessed; - } - else - { - if ( (m_State & State.Warned) == 0 ) + if ((m_State & State.Accessed) == 0) { - m_State |= State.Warned; - - try + m_State |= State.Accessed; + } + else + { + if ((m_State & State.Warned) == 0) { - using ( StreamWriter op = new StreamWriter( "net_opt.log", true ) ) + m_State |= State.Warned; + + try + { + using (StreamWriter op = new StreamWriter("net_opt.log", true)) + { + op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", this.GetType()); + op.WriteLine(new System.Diagnostics.StackTrace()); + } + } + catch { - op.WriteLine( "Redundant compile for packet {0}, use Acquire() and Release()", this.GetType() ); - op.WriteLine( new System.Diagnostics.StackTrace() ); } } - catch - { - } + + m_CompiledBuffer = new byte[0]; + m_CompiledLength = 0; + + length = m_CompiledLength; + return m_CompiledBuffer; } - m_CompiledBuffer = new byte[0]; - m_CompiledLength = 0; - - length = m_CompiledLength; - return m_CompiledBuffer; + InternalCompile(compress); } - InternalCompile( compress ); + length = m_CompiledLength; + return m_CompiledBuffer; } - - length = m_CompiledLength; - return m_CompiledBuffer; } private void InternalCompile( bool compress ) @@ -4578,41 +4592,49 @@ namespace Server.Network m_CompiledBuffer = ms.GetBuffer(); int length = (int)ms.Length; - if ( compress ) - { - m_CompiledBuffer = Compression.Compress( - m_CompiledBuffer, 0, length, - ref length - ); - - if ( m_CompiledBuffer == null ) - { - Console.WriteLine( "Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", m_PacketID, GetType().Name, length ); - using ( StreamWriter op = new StreamWriter( "compression_overflow.log", true ) ) + if ( compress ) { + byte[] buffer; + lock (m_CompressorBuffers) + buffer = m_CompressorBuffers.AcquireBuffer(); + + Compression.Compress(m_CompiledBuffer, 0, length, buffer, ref length); + + if (length <= 0) { + Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})", m_PacketID, GetType().Name, length); + using (StreamWriter op = new StreamWriter("compression_overflow.log", true)) { op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})", DateTime.UtcNow, m_PacketID, GetType().Name, length); - op.WriteLine( new System.Diagnostics.StackTrace() ); + op.WriteLine(new System.Diagnostics.StackTrace()); } - } - } + } else { + m_CompiledLength = length; - if ( m_CompiledBuffer != null ) - { + if (length > BufferSize || (m_State & State.Static) != 0) { + m_CompiledBuffer = new byte[length]; + } else { + lock (m_Buffers) + m_CompiledBuffer = m_Buffers.AcquireBuffer(); + m_State |= State.Buffered; + } + + Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length); + + lock (m_CompressorBuffers) + m_CompressorBuffers.ReleaseBuffer(buffer); + } + } else if (length > 0) { + byte[] old = m_CompiledBuffer; m_CompiledLength = length; - byte[] old = m_CompiledBuffer; - - if ( length > BufferSize || (m_State & State.Static) != 0 ) - { + if ( length > BufferSize || (m_State & State.Static) != 0 ) { m_CompiledBuffer = new byte[length]; - } - else - { - m_CompiledBuffer = m_Buffers.AcquireBuffer(); + } else { + lock (m_Buffers) + m_CompiledBuffer = m_Buffers.AcquireBuffer(); m_State |= State.Buffered; } - Buffer.BlockCopy( old, 0, m_CompiledBuffer, 0, length ); + Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length); } PacketWriter.ReleaseInstance( m_Stream ); diff --git a/Server/Network/SendQueue.cs b/Server/Network/SendQueue.cs index b4920b0ba..f0f3d223d 100644 --- a/Server/Network/SendQueue.cs +++ b/Server/Network/SendQueue.cs @@ -104,22 +104,27 @@ namespace Server.Network { if ( m_CoalesceBufferSize == value ) return; - if ( m_UnusedBuffers != null ) - m_UnusedBuffers.Free(); + BufferPool old = m_UnusedBuffers; - m_CoalesceBufferSize = value; - m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize ); + lock (old) { + if ( m_UnusedBuffers != null ) + m_UnusedBuffers.Free(); + + m_CoalesceBufferSize = value; + m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize ); + } } } public static byte[] AcquireBuffer() { - return m_UnusedBuffers.AcquireBuffer(); + lock (m_UnusedBuffers) + return m_UnusedBuffers.AcquireBuffer(); } public static void ReleaseBuffer( byte[] buffer ) { - if ( buffer != null && buffer.Length == m_CoalesceBufferSize ) { - m_UnusedBuffers.ReleaseBuffer( buffer ); - } + lock (m_UnusedBuffers) + if ( buffer != null && buffer.Length == m_CoalesceBufferSize ) + m_UnusedBuffers.ReleaseBuffer( buffer ); } private Queue _pending; @@ -143,15 +148,9 @@ namespace Server.Network { } public Gram CheckFlushReady() { - Gram gram = null; - - if ( _pending.Count == 0 && _buffered != null ) { - gram = _buffered; - - _pending.Enqueue( _buffered ); - _buffered = null; - } - + Gram gram = _buffered; + _pending.Enqueue(_buffered); + _buffered = null; return gram; } @@ -169,7 +168,7 @@ namespace Server.Network { return gram; } - private const int PendingCap = 96 * 1024; + private const int PendingCap = 128 * 1024; public Gram Enqueue( byte[] buffer, int length ) { return Enqueue( buffer, 0, length );