Fixes code according to modern code style. Fixes a few expression bugs.
This commit is contained in:
parent
89eea25e5f
commit
970fd563b2
3324 changed files with 441118 additions and 433755 deletions
|
|
@ -19,187 +19,187 @@
|
|||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class AggressorInfo
|
||||
{
|
||||
private Mobile m_Attacker, m_Defender;
|
||||
private DateTime m_LastCombatTime;
|
||||
private bool m_CanReportMurder;
|
||||
private bool m_Reported;
|
||||
private bool m_CriminalAggression;
|
||||
public class AggressorInfo
|
||||
{
|
||||
private static Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>();
|
||||
private Mobile m_Attacker, m_Defender;
|
||||
private bool m_CanReportMurder;
|
||||
private bool m_CriminalAggression;
|
||||
private DateTime m_LastCombatTime;
|
||||
|
||||
private bool m_Queued;
|
||||
private bool m_Queued;
|
||||
private bool m_Reported;
|
||||
|
||||
private static Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>();
|
||||
private AggressorInfo(Mobile attacker, Mobile defender, bool criminal)
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
|
||||
public static AggressorInfo Create( Mobile attacker, Mobile defender, bool criminal )
|
||||
{
|
||||
AggressorInfo info;
|
||||
m_CanReportMurder = criminal;
|
||||
m_CriminalAggression = criminal;
|
||||
|
||||
if ( m_Pool.Count > 0 )
|
||||
{
|
||||
info = m_Pool.Dequeue();
|
||||
Refresh();
|
||||
}
|
||||
|
||||
info.m_Attacker = attacker;
|
||||
info.m_Defender = defender;
|
||||
public static TimeSpan ExpireDelay{ get; set; } = TimeSpan.FromMinutes(2.0);
|
||||
|
||||
info.m_CanReportMurder = criminal;
|
||||
info.m_CriminalAggression = criminal;
|
||||
public bool Expired
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
info.m_Queued = false;
|
||||
return m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= m_LastCombatTime + ExpireDelay;
|
||||
}
|
||||
}
|
||||
|
||||
info.Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
info = new AggressorInfo( attacker, defender, criminal );
|
||||
}
|
||||
public bool CriminalAggression
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
return info;
|
||||
}
|
||||
return m_CriminalAggression;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
public void Free()
|
||||
{
|
||||
if ( m_Queued )
|
||||
return;
|
||||
m_CriminalAggression = value;
|
||||
}
|
||||
}
|
||||
|
||||
m_Queued = true;
|
||||
m_Pool.Enqueue( this );
|
||||
}
|
||||
public Mobile Attacker
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
private AggressorInfo( Mobile attacker, Mobile defender, bool criminal )
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
return m_Attacker;
|
||||
}
|
||||
}
|
||||
|
||||
m_CanReportMurder = criminal;
|
||||
m_CriminalAggression = criminal;
|
||||
public Mobile Defender
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
Refresh();
|
||||
}
|
||||
return m_Defender;
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSpan ExpireDelay { get; set; } = TimeSpan.FromMinutes( 2.0 );
|
||||
public DateTime LastCombatTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
public static void DumpAccess()
|
||||
{
|
||||
using ( StreamWriter op = new StreamWriter( "warnings.log", true ) )
|
||||
{
|
||||
op.WriteLine( "Warning: Access to queued AggressorInfo:" );
|
||||
op.WriteLine( new System.Diagnostics.StackTrace() );
|
||||
op.WriteLine();
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
return m_LastCombatTime;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Expired
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
public bool Reported
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
return ( m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= (m_LastCombatTime + ExpireDelay) );
|
||||
}
|
||||
}
|
||||
return m_Reported;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
public bool CriminalAggression
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
m_Reported = value;
|
||||
}
|
||||
}
|
||||
|
||||
return m_CriminalAggression;
|
||||
}
|
||||
set
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
public bool CanReportMurder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
m_CriminalAggression = value;
|
||||
}
|
||||
}
|
||||
return m_CanReportMurder;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
public Mobile Attacker
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
m_CanReportMurder = value;
|
||||
}
|
||||
}
|
||||
|
||||
return m_Attacker;
|
||||
}
|
||||
}
|
||||
public static AggressorInfo Create(Mobile attacker, Mobile defender, bool criminal)
|
||||
{
|
||||
AggressorInfo info;
|
||||
|
||||
public Mobile Defender
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
if (m_Pool.Count > 0)
|
||||
{
|
||||
info = m_Pool.Dequeue();
|
||||
|
||||
return m_Defender;
|
||||
}
|
||||
}
|
||||
info.m_Attacker = attacker;
|
||||
info.m_Defender = defender;
|
||||
|
||||
public DateTime LastCombatTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
info.m_CanReportMurder = criminal;
|
||||
info.m_CriminalAggression = criminal;
|
||||
|
||||
return m_LastCombatTime;
|
||||
}
|
||||
}
|
||||
info.m_Queued = false;
|
||||
|
||||
public bool Reported
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
info.Refresh();
|
||||
}
|
||||
else
|
||||
{
|
||||
info = new AggressorInfo(attacker, defender, criminal);
|
||||
}
|
||||
|
||||
return m_Reported;
|
||||
}
|
||||
set
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
return info;
|
||||
}
|
||||
|
||||
m_Reported = value;
|
||||
}
|
||||
}
|
||||
public void Free()
|
||||
{
|
||||
if (m_Queued)
|
||||
return;
|
||||
|
||||
public bool CanReportMurder
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
m_Queued = true;
|
||||
m_Pool.Enqueue(this);
|
||||
}
|
||||
|
||||
return m_CanReportMurder;
|
||||
}
|
||||
set
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
public static void DumpAccess()
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("warnings.log", true))
|
||||
{
|
||||
op.WriteLine("Warning: Access to queued AggressorInfo:");
|
||||
op.WriteLine(new StackTrace());
|
||||
op.WriteLine();
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
m_CanReportMurder = value;
|
||||
}
|
||||
}
|
||||
public void Refresh()
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if ( m_Queued )
|
||||
DumpAccess();
|
||||
|
||||
m_LastCombatTime = DateTime.UtcNow;
|
||||
m_Reported = false;
|
||||
}
|
||||
}
|
||||
m_LastCombatTime = DateTime.UtcNow;
|
||||
m_Reported = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +26,7 @@ using System.Runtime.InteropServices;
|
|||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
//
|
||||
[assembly: AssemblyTitle("RunUO Server Core")] //Having just RunUO there is reundant, ie, RunUO.exe with the word 'RunUO' under it
|
||||
[assembly: AssemblyTitle("RunUO Server Core")] //Having just RunUO there is reundant, ie, RunUO.exe with the word 'RunUO' under it
|
||||
[assembly: AssemblyDescription("UO Server Software")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("RunUO")]
|
||||
|
|
@ -77,4 +77,4 @@ using System.Runtime.InteropServices;
|
|||
[assembly: AssemblyKeyFile("")]
|
||||
[assembly: AssemblyKeyName("")]
|
||||
|
||||
[assembly: ComVisible(false)]
|
||||
[assembly: ComVisible(false)]
|
||||
|
|
@ -24,156 +24,142 @@ using System.Reflection;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
[AttributeUsage( AttributeTargets.Property )]
|
||||
public class HueAttribute : Attribute
|
||||
{
|
||||
public HueAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class HueAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Property )]
|
||||
public class BodyAttribute : Attribute
|
||||
{
|
||||
public BodyAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class BodyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )]
|
||||
public class PropertyObjectAttribute : Attribute
|
||||
{
|
||||
public PropertyObjectAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class PropertyObjectAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )]
|
||||
public class NoSortAttribute : Attribute
|
||||
{
|
||||
public NoSortAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class NoSortAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Method )]
|
||||
public class CallPriorityAttribute : Attribute
|
||||
{
|
||||
public int Priority { get; set; }
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class CallPriorityAttribute : Attribute
|
||||
{
|
||||
public CallPriorityAttribute(int priority)
|
||||
{
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
public CallPriorityAttribute( int priority )
|
||||
{
|
||||
Priority = priority;
|
||||
}
|
||||
}
|
||||
public int Priority{ get; set; }
|
||||
}
|
||||
|
||||
public class CallPriorityComparer : IComparer<MethodInfo>
|
||||
{
|
||||
public int Compare( MethodInfo x, MethodInfo y )
|
||||
{
|
||||
if ( x == null && y == null )
|
||||
return 0;
|
||||
public class CallPriorityComparer : IComparer<MethodInfo>
|
||||
{
|
||||
public int Compare(MethodInfo x, MethodInfo y)
|
||||
{
|
||||
if (x == null && y == null)
|
||||
return 0;
|
||||
|
||||
if ( x == null )
|
||||
return 1;
|
||||
if (x == null)
|
||||
return 1;
|
||||
|
||||
if ( y == null )
|
||||
return -1;
|
||||
if (y == null)
|
||||
return -1;
|
||||
|
||||
var xPriority = GetPriority( x );
|
||||
var yPriority = GetPriority( y );
|
||||
int xPriority = GetPriority(x);
|
||||
int yPriority = GetPriority(y);
|
||||
|
||||
if ( xPriority > yPriority )
|
||||
return 1;
|
||||
if (xPriority > yPriority)
|
||||
return 1;
|
||||
|
||||
if ( xPriority < yPriority )
|
||||
return -1;
|
||||
if (xPriority < yPriority)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int GetPriority( MethodInfo mi )
|
||||
{
|
||||
object[] objs = mi.GetCustomAttributes( typeof( CallPriorityAttribute ), true );
|
||||
private int GetPriority(MethodInfo mi)
|
||||
{
|
||||
object[] objs = mi.GetCustomAttributes(typeof(CallPriorityAttribute), true);
|
||||
|
||||
if ( objs.Length == 0 )
|
||||
return 0;
|
||||
if (objs.Length == 0)
|
||||
return 0;
|
||||
|
||||
if ( !(objs[0] is CallPriorityAttribute attr) )
|
||||
return 0;
|
||||
if (!(objs[0] is CallPriorityAttribute attr))
|
||||
return 0;
|
||||
|
||||
return attr.Priority;
|
||||
}
|
||||
}
|
||||
return attr.Priority;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Class )]
|
||||
public class TypeAliasAttribute : Attribute
|
||||
{
|
||||
public string[] Aliases { get; }
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TypeAliasAttribute : Attribute
|
||||
{
|
||||
public TypeAliasAttribute(params string[] aliases)
|
||||
{
|
||||
Aliases = aliases;
|
||||
}
|
||||
|
||||
public TypeAliasAttribute( params string[] aliases )
|
||||
{
|
||||
Aliases = aliases;
|
||||
}
|
||||
}
|
||||
public string[] Aliases{ get; }
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct )]
|
||||
public class ParsableAttribute : Attribute
|
||||
{
|
||||
public ParsableAttribute()
|
||||
{
|
||||
}
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class ParsableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum )]
|
||||
public class CustomEnumAttribute : Attribute
|
||||
{
|
||||
public string[] Names { get; }
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
|
||||
public class CustomEnumAttribute : Attribute
|
||||
{
|
||||
public CustomEnumAttribute(string[] names)
|
||||
{
|
||||
Names = names;
|
||||
}
|
||||
|
||||
public CustomEnumAttribute( string[] names )
|
||||
{
|
||||
Names = names;
|
||||
}
|
||||
}
|
||||
public string[] Names{ get; }
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Constructor )]
|
||||
public class ConstructibleAttribute : Attribute
|
||||
{
|
||||
public AccessLevel AccessLevel { get; set; }
|
||||
[AttributeUsage(AttributeTargets.Constructor)]
|
||||
public class ConstructibleAttribute : Attribute
|
||||
{
|
||||
public ConstructibleAttribute() :
|
||||
this(AccessLevel.Player) //Lowest accesslevel for current functionality (Level determined by access to [add)
|
||||
{
|
||||
}
|
||||
|
||||
public ConstructibleAttribute() : this( AccessLevel.Player ) //Lowest accesslevel for current functionality (Level determined by access to [add)
|
||||
{
|
||||
}
|
||||
public ConstructibleAttribute(AccessLevel accessLevel)
|
||||
{
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
|
||||
public ConstructibleAttribute( AccessLevel accessLevel )
|
||||
{
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
}
|
||||
public AccessLevel AccessLevel{ get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage( AttributeTargets.Property )]
|
||||
public class CommandPropertyAttribute : Attribute
|
||||
{
|
||||
public AccessLevel ReadLevel { get; }
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class CommandPropertyAttribute : Attribute
|
||||
{
|
||||
public CommandPropertyAttribute(AccessLevel level, bool readOnly)
|
||||
{
|
||||
ReadLevel = level;
|
||||
ReadOnly = readOnly;
|
||||
}
|
||||
|
||||
public AccessLevel WriteLevel { get; }
|
||||
public CommandPropertyAttribute(AccessLevel level) : this(level, level)
|
||||
{
|
||||
}
|
||||
|
||||
public bool ReadOnly { get; }
|
||||
public CommandPropertyAttribute(AccessLevel readLevel, AccessLevel writeLevel)
|
||||
{
|
||||
ReadLevel = readLevel;
|
||||
WriteLevel = writeLevel;
|
||||
}
|
||||
|
||||
public CommandPropertyAttribute( AccessLevel level, bool readOnly )
|
||||
{
|
||||
ReadLevel = level;
|
||||
ReadOnly = readOnly;
|
||||
}
|
||||
public AccessLevel ReadLevel{ get; }
|
||||
|
||||
public CommandPropertyAttribute( AccessLevel level ) : this( level, level )
|
||||
{
|
||||
}
|
||||
public AccessLevel WriteLevel{ get; }
|
||||
|
||||
public CommandPropertyAttribute( AccessLevel readLevel, AccessLevel writeLevel )
|
||||
{
|
||||
ReadLevel = readLevel;
|
||||
WriteLevel = writeLevel;
|
||||
}
|
||||
}
|
||||
}
|
||||
public bool ReadOnly{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -22,85 +22,85 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class BuyItemStateComparer : IComparer<BuyItemState>
|
||||
{
|
||||
public int Compare( BuyItemState l, BuyItemState r )
|
||||
{
|
||||
if ( l == null && r == null ) return 0;
|
||||
if ( l == null ) return -1;
|
||||
if ( r == null ) return 1;
|
||||
public class BuyItemStateComparer : IComparer<BuyItemState>
|
||||
{
|
||||
public int Compare(BuyItemState l, BuyItemState r)
|
||||
{
|
||||
if (l == null && r == null) return 0;
|
||||
if (l == null) return -1;
|
||||
if (r == null) return 1;
|
||||
|
||||
return l.MySerial.CompareTo( r.MySerial );
|
||||
}
|
||||
}
|
||||
return l.MySerial.CompareTo(r.MySerial);
|
||||
}
|
||||
}
|
||||
|
||||
public class BuyItemResponse
|
||||
{
|
||||
public BuyItemResponse( Serial serial, int amount )
|
||||
{
|
||||
Serial = serial;
|
||||
Amount = amount;
|
||||
}
|
||||
public class BuyItemResponse
|
||||
{
|
||||
public BuyItemResponse(Serial serial, int amount)
|
||||
{
|
||||
Serial = serial;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Serial Serial { get; }
|
||||
public Serial Serial{ get; }
|
||||
|
||||
public int Amount { get; }
|
||||
}
|
||||
public int Amount{ get; }
|
||||
}
|
||||
|
||||
public class SellItemResponse
|
||||
{
|
||||
public SellItemResponse( Item i, int amount )
|
||||
{
|
||||
Item = i;
|
||||
Amount = amount;
|
||||
}
|
||||
public class SellItemResponse
|
||||
{
|
||||
public SellItemResponse(Item i, int amount)
|
||||
{
|
||||
Item = i;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Item Item { get; }
|
||||
public Item Item{ get; }
|
||||
|
||||
public int Amount { get; }
|
||||
}
|
||||
public int Amount{ get; }
|
||||
}
|
||||
|
||||
public class SellItemState
|
||||
{
|
||||
public SellItemState( Item item, int price, string name )
|
||||
{
|
||||
Item = item;
|
||||
Price = price;
|
||||
Name = name;
|
||||
}
|
||||
public class SellItemState
|
||||
{
|
||||
public SellItemState(Item item, int price, string name)
|
||||
{
|
||||
Item = item;
|
||||
Price = price;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public Item Item { get; }
|
||||
public Item Item{ get; }
|
||||
|
||||
public int Price { get; }
|
||||
public int Price{ get; }
|
||||
|
||||
public string Name { get; }
|
||||
}
|
||||
public string Name{ get; }
|
||||
}
|
||||
|
||||
public class BuyItemState
|
||||
{
|
||||
public BuyItemState( string name, Serial cont, Serial serial, int price, int amount, int itemID, int hue )
|
||||
{
|
||||
Description = name;
|
||||
ContainerSerial = cont;
|
||||
MySerial = serial;
|
||||
Price = price;
|
||||
Amount = amount;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
public class BuyItemState
|
||||
{
|
||||
public BuyItemState(string name, Serial cont, Serial serial, int price, int amount, int itemID, int hue)
|
||||
{
|
||||
Description = name;
|
||||
ContainerSerial = cont;
|
||||
MySerial = serial;
|
||||
Price = price;
|
||||
Amount = amount;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
public int Price { get; }
|
||||
public int Price{ get; }
|
||||
|
||||
public Serial MySerial { get; }
|
||||
public Serial MySerial{ get; }
|
||||
|
||||
public Serial ContainerSerial { get; }
|
||||
public Serial ContainerSerial{ get; }
|
||||
|
||||
public int ItemID { get; }
|
||||
public int ItemID{ get; }
|
||||
|
||||
public int Amount { get; }
|
||||
public int Amount{ get; }
|
||||
|
||||
public int Hue { get; }
|
||||
public int Hue{ get; }
|
||||
|
||||
public string Description { get; }
|
||||
}
|
||||
}
|
||||
public string Description{ get; }
|
||||
}
|
||||
}
|
||||
321
Server/Body.cs
321
Server/Body.cs
|
|
@ -23,196 +23,197 @@ using System.IO;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public enum BodyType : byte
|
||||
{
|
||||
Empty,
|
||||
Monster,
|
||||
Sea,
|
||||
Animal,
|
||||
Human,
|
||||
Equipment
|
||||
}
|
||||
public enum BodyType : byte
|
||||
{
|
||||
Empty,
|
||||
Monster,
|
||||
Sea,
|
||||
Animal,
|
||||
Human,
|
||||
Equipment
|
||||
}
|
||||
|
||||
public struct Body
|
||||
{
|
||||
private static BodyType[] m_Types;
|
||||
public struct Body
|
||||
{
|
||||
private static BodyType[] m_Types;
|
||||
|
||||
static Body()
|
||||
{
|
||||
if ( File.Exists( "Data/bodyTable.cfg" ) )
|
||||
{
|
||||
using ( StreamReader ip = new StreamReader( "Data/bodyTable.cfg" ) )
|
||||
{
|
||||
m_Types = new BodyType[0x1000];
|
||||
static Body()
|
||||
{
|
||||
if (File.Exists("Data/bodyTable.cfg"))
|
||||
{
|
||||
using (StreamReader ip = new StreamReader("Data/bodyTable.cfg"))
|
||||
{
|
||||
m_Types = new BodyType[0x1000];
|
||||
|
||||
string line;
|
||||
string line;
|
||||
|
||||
while ( (line = ip.ReadLine()) != null )
|
||||
{
|
||||
if ( line.Length == 0 || line.StartsWith( "#" ) )
|
||||
continue;
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length == 0 || line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
string[] split = line.Split( '\t' );
|
||||
string[] split = line.Split('\t');
|
||||
|
||||
BodyType type;
|
||||
int bodyID;
|
||||
BodyType type;
|
||||
int bodyID;
|
||||
|
||||
if ( int.TryParse( split[0], out bodyID ) && Enum.TryParse( split[1], true, out type ) && bodyID >= 0 && bodyID < m_Types.Length )
|
||||
{
|
||||
m_Types[bodyID] = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine( "Warning: Invalid bodyTable entry:" );
|
||||
Console.WriteLine( line );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine( "Warning: Data/bodyTable.cfg does not exist" );
|
||||
if (int.TryParse(split[0], out bodyID) && Enum.TryParse(split[1], true, out type) && bodyID >= 0 &&
|
||||
bodyID < m_Types.Length)
|
||||
{
|
||||
m_Types[bodyID] = type;
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: Invalid bodyTable entry:");
|
||||
Console.WriteLine(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Warning: Data/bodyTable.cfg does not exist");
|
||||
|
||||
m_Types = new BodyType[0];
|
||||
}
|
||||
}
|
||||
m_Types = new BodyType[0];
|
||||
}
|
||||
}
|
||||
|
||||
public Body( int bodyID )
|
||||
{
|
||||
BodyID = bodyID;
|
||||
}
|
||||
public Body(int bodyID)
|
||||
{
|
||||
BodyID = bodyID;
|
||||
}
|
||||
|
||||
public BodyType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( BodyID >= 0 && BodyID < m_Types.Length )
|
||||
return m_Types[BodyID];
|
||||
return BodyType.Empty;
|
||||
}
|
||||
}
|
||||
public BodyType Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if (BodyID >= 0 && BodyID < m_Types.Length)
|
||||
return m_Types[BodyID];
|
||||
return BodyType.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsHuman => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Human
|
||||
&& BodyID != 402
|
||||
&& BodyID != 403
|
||||
&& BodyID != 607
|
||||
&& BodyID != 608
|
||||
&& BodyID != 694
|
||||
&& BodyID != 695
|
||||
&& BodyID != 970;
|
||||
public bool IsHuman => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Human
|
||||
&& BodyID != 402
|
||||
&& BodyID != 403
|
||||
&& BodyID != 607
|
||||
&& BodyID != 608
|
||||
&& BodyID != 694
|
||||
&& BodyID != 695
|
||||
&& BodyID != 970;
|
||||
|
||||
public bool IsGargoyle => BodyID == 666
|
||||
|| BodyID == 667
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695;
|
||||
public bool IsGargoyle => BodyID == 666
|
||||
|| BodyID == 667
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695;
|
||||
|
||||
public bool IsMale => BodyID == 183
|
||||
|| BodyID == 185
|
||||
|| BodyID == 400
|
||||
|| BodyID == 402
|
||||
|| BodyID == 605
|
||||
|| BodyID == 607
|
||||
|| BodyID == 666
|
||||
|| BodyID == 694
|
||||
|| BodyID == 750;
|
||||
public bool IsMale => BodyID == 183
|
||||
|| BodyID == 185
|
||||
|| BodyID == 400
|
||||
|| BodyID == 402
|
||||
|| BodyID == 605
|
||||
|| BodyID == 607
|
||||
|| BodyID == 666
|
||||
|| BodyID == 694
|
||||
|| BodyID == 750;
|
||||
|
||||
public bool IsFemale => BodyID == 184
|
||||
|| BodyID == 186
|
||||
|| BodyID == 401
|
||||
|| BodyID == 403
|
||||
|| BodyID == 606
|
||||
|| BodyID == 608
|
||||
|| BodyID == 667
|
||||
|| BodyID == 695
|
||||
|| BodyID == 751;
|
||||
public bool IsFemale => BodyID == 184
|
||||
|| BodyID == 186
|
||||
|| BodyID == 401
|
||||
|| BodyID == 403
|
||||
|| BodyID == 606
|
||||
|| BodyID == 608
|
||||
|| BodyID == 667
|
||||
|| BodyID == 695
|
||||
|| BodyID == 751;
|
||||
|
||||
public bool IsGhost => BodyID == 402
|
||||
|| BodyID == 403
|
||||
|| BodyID == 607
|
||||
|| BodyID == 608
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695
|
||||
|| BodyID == 970;
|
||||
public bool IsGhost => BodyID == 402
|
||||
|| BodyID == 403
|
||||
|| BodyID == 607
|
||||
|| BodyID == 608
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695
|
||||
|| BodyID == 970;
|
||||
|
||||
public bool IsMonster => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Monster;
|
||||
public bool IsMonster => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Monster;
|
||||
|
||||
public bool IsAnimal => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Animal;
|
||||
public bool IsAnimal => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Animal;
|
||||
|
||||
public bool IsEmpty => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Empty;
|
||||
public bool IsEmpty => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Empty;
|
||||
|
||||
public bool IsSea => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Sea;
|
||||
public bool IsSea => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Sea;
|
||||
|
||||
public bool IsEquipment => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Equipment;
|
||||
public bool IsEquipment => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Equipment;
|
||||
|
||||
public int BodyID { get; }
|
||||
public int BodyID{ get; }
|
||||
|
||||
public static implicit operator int( Body a )
|
||||
{
|
||||
return a.BodyID;
|
||||
}
|
||||
public static implicit operator int(Body a)
|
||||
{
|
||||
return a.BodyID;
|
||||
}
|
||||
|
||||
public static implicit operator Body( int a )
|
||||
{
|
||||
return new Body( a );
|
||||
}
|
||||
public static implicit operator Body(int a)
|
||||
{
|
||||
return new Body(a);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{BodyID:X}";
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{BodyID:X}";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return BodyID;
|
||||
}
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return BodyID;
|
||||
}
|
||||
|
||||
public override bool Equals( object o )
|
||||
{
|
||||
if ( !(o is Body) ) return false;
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
if (!(o is Body)) return false;
|
||||
|
||||
return ((Body)o).BodyID == BodyID;
|
||||
}
|
||||
return ((Body)o).BodyID == BodyID;
|
||||
}
|
||||
|
||||
public static bool operator == ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID == r.BodyID;
|
||||
}
|
||||
public static bool operator ==(Body l, Body r)
|
||||
{
|
||||
return l.BodyID == r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator != ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID != r.BodyID;
|
||||
}
|
||||
public static bool operator !=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID != r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator > ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID > r.BodyID;
|
||||
}
|
||||
public static bool operator >(Body l, Body r)
|
||||
{
|
||||
return l.BodyID > r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator >= ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID >= r.BodyID;
|
||||
}
|
||||
public static bool operator >=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID >= r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator < ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID < r.BodyID;
|
||||
}
|
||||
public static bool operator <(Body l, Body r)
|
||||
{
|
||||
return l.BodyID < r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator <= ( Body l, Body r )
|
||||
{
|
||||
return l.BodyID <= r.BodyID;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static bool operator <=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID <= r.BodyID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,246 +19,247 @@
|
|||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.Collections;
|
||||
using System.Text;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum ClientType
|
||||
{
|
||||
Regular,
|
||||
UOTD,
|
||||
God,
|
||||
SA
|
||||
}
|
||||
public enum ClientType
|
||||
{
|
||||
Regular,
|
||||
UOTD,
|
||||
God,
|
||||
SA
|
||||
}
|
||||
|
||||
public class ClientVersion : IComparable, IComparer
|
||||
{
|
||||
public int Major { get; }
|
||||
public class ClientVersion : IComparable, IComparer
|
||||
{
|
||||
public ClientVersion(int maj, int min, int rev, int pat) : this(maj, min, rev, pat, ClientType.Regular)
|
||||
{
|
||||
}
|
||||
|
||||
public int Minor { get; }
|
||||
public ClientVersion(int maj, int min, int rev, int pat, ClientType type)
|
||||
{
|
||||
Major = maj;
|
||||
Minor = min;
|
||||
Revision = rev;
|
||||
Patch = pat;
|
||||
Type = type;
|
||||
|
||||
public int Revision { get; }
|
||||
SourceString = _ToStringImpl();
|
||||
}
|
||||
|
||||
public int Patch { get; }
|
||||
public ClientVersion(string fmt)
|
||||
{
|
||||
SourceString = fmt;
|
||||
|
||||
public ClientType Type { get; }
|
||||
try
|
||||
{
|
||||
fmt = fmt.ToLower();
|
||||
|
||||
public string SourceString { get; }
|
||||
int br1 = fmt.IndexOf('.');
|
||||
int br2 = fmt.IndexOf('.', br1 + 1);
|
||||
|
||||
public ClientVersion( int maj, int min, int rev, int pat ) : this( maj, min, rev, pat, ClientType.Regular )
|
||||
{
|
||||
}
|
||||
int br3 = br2 + 1;
|
||||
while (br3 < fmt.Length && char.IsDigit(fmt, br3))
|
||||
br3++;
|
||||
|
||||
public ClientVersion( int maj, int min, int rev, int pat, ClientType type )
|
||||
{
|
||||
Major = maj;
|
||||
Minor = min;
|
||||
Revision = rev;
|
||||
Patch = pat;
|
||||
Type = type;
|
||||
Major = Utility.ToInt32(fmt.Substring(0, br1));
|
||||
Minor = Utility.ToInt32(fmt.Substring(br1 + 1, br2 - br1 - 1));
|
||||
Revision = Utility.ToInt32(fmt.Substring(br2 + 1, br3 - br2 - 1));
|
||||
|
||||
SourceString = _ToStringImpl();
|
||||
}
|
||||
if (br3 < fmt.Length)
|
||||
{
|
||||
if (Major <= 5 && Minor <= 0 && Revision <= 6) //Anything before 5.0.7
|
||||
{
|
||||
if (!char.IsWhiteSpace(fmt, br3))
|
||||
Patch = fmt[br3] - 'a' + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Patch = Utility.ToInt32(fmt.Substring(br3 + 1, fmt.Length - br3 - 1));
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator == ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) == 0 );
|
||||
}
|
||||
if (fmt.IndexOf("god") >= 0 || fmt.IndexOf("gq") >= 0)
|
||||
Type = ClientType.God;
|
||||
else if (fmt.IndexOf("third dawn") >= 0 || fmt.IndexOf("uo:td") >= 0 || fmt.IndexOf("uotd") >= 0 ||
|
||||
fmt.IndexOf("uo3d") >= 0 || fmt.IndexOf("uo:3d") >= 0)
|
||||
Type = ClientType.UOTD;
|
||||
else
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Major = 0;
|
||||
Minor = 0;
|
||||
Revision = 0;
|
||||
Patch = 0;
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool operator != ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) != 0 );
|
||||
}
|
||||
public int Major{ get; }
|
||||
|
||||
public static bool operator >= ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) >= 0 );
|
||||
}
|
||||
public int Minor{ get; }
|
||||
|
||||
public static bool operator > ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) > 0 );
|
||||
}
|
||||
public int Revision{ get; }
|
||||
|
||||
public static bool operator <= ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) <= 0 );
|
||||
}
|
||||
public int Patch{ get; }
|
||||
|
||||
public static bool operator < ( ClientVersion l, ClientVersion r )
|
||||
{
|
||||
return ( Compare( l, r ) < 0 );
|
||||
}
|
||||
public ClientType Type{ get; }
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Major ^ Minor ^ Revision ^ Patch ^ (int)Type;
|
||||
}
|
||||
public string SourceString{ get; }
|
||||
|
||||
public override bool Equals( object obj )
|
||||
{
|
||||
if ( obj == null )
|
||||
return false;
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return 1;
|
||||
|
||||
ClientVersion v = obj as ClientVersion;
|
||||
ClientVersion o = obj as ClientVersion;
|
||||
|
||||
if ( v == null )
|
||||
return false;
|
||||
if (o == null)
|
||||
throw new ArgumentException();
|
||||
|
||||
return Major == v.Major
|
||||
&& Minor == v.Minor
|
||||
&& Revision == v.Revision
|
||||
&& Patch == v.Patch
|
||||
&& Type == v.Type;
|
||||
}
|
||||
if (Major > o.Major)
|
||||
return 1;
|
||||
if (Major < o.Major)
|
||||
return -1;
|
||||
if (Minor > o.Minor)
|
||||
return 1;
|
||||
if (Minor < o.Minor)
|
||||
return -1;
|
||||
if (Revision > o.Revision)
|
||||
return 1;
|
||||
if (Revision < o.Revision)
|
||||
return -1;
|
||||
if (Patch > o.Patch)
|
||||
return 1;
|
||||
if (Patch < o.Patch)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
private string _ToStringImpl()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(16);
|
||||
public int Compare(object x, object y)
|
||||
{
|
||||
if (IsNull(x) && IsNull(y))
|
||||
return 0;
|
||||
if (IsNull(x))
|
||||
return -1;
|
||||
if (IsNull(y))
|
||||
return 1;
|
||||
|
||||
builder.Append(Major);
|
||||
builder.Append('.');
|
||||
builder.Append(Minor);
|
||||
builder.Append('.');
|
||||
builder.Append(Revision);
|
||||
ClientVersion a = x as ClientVersion;
|
||||
ClientVersion b = y as ClientVersion;
|
||||
|
||||
if (Major <= 5 && Minor <= 0 && Revision <= 6) //Anything before 5.0.7
|
||||
{
|
||||
if (Patch > 0)
|
||||
builder.Append((char)('a' + (Patch - 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('.');
|
||||
builder.Append(Patch);
|
||||
}
|
||||
if (IsNull(a) || IsNull(b))
|
||||
throw new ArgumentException();
|
||||
|
||||
if (Type != ClientType.Regular)
|
||||
{
|
||||
builder.Append(' ');
|
||||
builder.Append(Type.ToString());
|
||||
}
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
public static bool operator ==(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) == 0;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _ToStringImpl();
|
||||
}
|
||||
public static bool operator !=(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) != 0;
|
||||
}
|
||||
|
||||
public ClientVersion( string fmt )
|
||||
{
|
||||
SourceString = fmt;
|
||||
public static bool operator >=(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) >= 0;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
fmt = fmt.ToLower();
|
||||
public static bool operator >(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) > 0;
|
||||
}
|
||||
|
||||
int br1 = fmt.IndexOf( '.' );
|
||||
int br2 = fmt.IndexOf( '.', br1 + 1 );
|
||||
public static bool operator <=(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) <= 0;
|
||||
}
|
||||
|
||||
int br3 = br2 + 1;
|
||||
while ( br3 < fmt.Length && char.IsDigit( fmt, br3 ) )
|
||||
br3++;
|
||||
public static bool operator <(ClientVersion l, ClientVersion r)
|
||||
{
|
||||
return Compare(l, r) < 0;
|
||||
}
|
||||
|
||||
Major = Utility.ToInt32( fmt.Substring( 0, br1 ) );
|
||||
Minor = Utility.ToInt32( fmt.Substring( br1 + 1, br2 - br1 - 1 ) );
|
||||
Revision = Utility.ToInt32( fmt.Substring( br2 + 1, br3 - br2 - 1 ) );
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return Major ^ Minor ^ Revision ^ Patch ^ (int)Type;
|
||||
}
|
||||
|
||||
if ( br3 < fmt.Length )
|
||||
{
|
||||
if ( Major <= 5 && Minor <= 0 && Revision <= 6 ) //Anything before 5.0.7
|
||||
{
|
||||
if ( !char.IsWhiteSpace( fmt, br3 ) )
|
||||
Patch = (fmt[br3] - 'a') + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Patch = Utility.ToInt32( fmt.Substring( br3+1, fmt.Length - br3 - 1 ) );
|
||||
}
|
||||
}
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
return false;
|
||||
|
||||
if ( fmt.IndexOf( "god" ) >= 0 || fmt.IndexOf( "gq" ) >= 0 )
|
||||
Type = ClientType.God;
|
||||
else if ( fmt.IndexOf( "third dawn" ) >= 0 || fmt.IndexOf( "uo:td" ) >= 0 || fmt.IndexOf( "uotd" ) >= 0 || fmt.IndexOf( "uo3d" ) >= 0 || fmt.IndexOf( "uo:3d" ) >= 0 )
|
||||
Type = ClientType.UOTD;
|
||||
else
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Major = 0;
|
||||
Minor = 0;
|
||||
Revision = 0;
|
||||
Patch = 0;
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
}
|
||||
ClientVersion v = obj as ClientVersion;
|
||||
|
||||
public int CompareTo( object obj )
|
||||
{
|
||||
if ( obj == null )
|
||||
return 1;
|
||||
if (v == null)
|
||||
return false;
|
||||
|
||||
ClientVersion o = obj as ClientVersion;
|
||||
return Major == v.Major
|
||||
&& Minor == v.Minor
|
||||
&& Revision == v.Revision
|
||||
&& Patch == v.Patch
|
||||
&& Type == v.Type;
|
||||
}
|
||||
|
||||
if ( o == null )
|
||||
throw new ArgumentException();
|
||||
private string _ToStringImpl()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(16);
|
||||
|
||||
if ( Major > o.Major )
|
||||
return 1;
|
||||
if ( Major < o.Major )
|
||||
return -1;
|
||||
if ( Minor > o.Minor )
|
||||
return 1;
|
||||
if ( Minor < o.Minor )
|
||||
return -1;
|
||||
if ( Revision > o.Revision )
|
||||
return 1;
|
||||
if ( Revision < o.Revision )
|
||||
return -1;
|
||||
if ( Patch > o.Patch )
|
||||
return 1;
|
||||
if ( Patch < o.Patch )
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
builder.Append(Major);
|
||||
builder.Append('.');
|
||||
builder.Append(Minor);
|
||||
builder.Append('.');
|
||||
builder.Append(Revision);
|
||||
|
||||
public static bool IsNull( object x )
|
||||
{
|
||||
return ReferenceEquals( x, null );
|
||||
}
|
||||
if (Major <= 5 && Minor <= 0 && Revision <= 6) //Anything before 5.0.7
|
||||
{
|
||||
if (Patch > 0)
|
||||
builder.Append((char)('a' + (Patch - 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('.');
|
||||
builder.Append(Patch);
|
||||
}
|
||||
|
||||
public int Compare( object x, object y )
|
||||
{
|
||||
if ( IsNull( x ) && IsNull( y ) )
|
||||
return 0;
|
||||
if ( IsNull( x ) )
|
||||
return -1;
|
||||
if ( IsNull( y ) )
|
||||
return 1;
|
||||
if (Type != ClientType.Regular)
|
||||
{
|
||||
builder.Append(' ');
|
||||
builder.Append(Type.ToString());
|
||||
}
|
||||
|
||||
ClientVersion a = x as ClientVersion;
|
||||
ClientVersion b = y as ClientVersion;
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
if ( IsNull( a ) || IsNull( b ) )
|
||||
throw new ArgumentException();
|
||||
public override string ToString()
|
||||
{
|
||||
return _ToStringImpl();
|
||||
}
|
||||
|
||||
return a.CompareTo( b );
|
||||
}
|
||||
public static bool IsNull(object x)
|
||||
{
|
||||
return ReferenceEquals(x, null);
|
||||
}
|
||||
|
||||
public static int Compare( ClientVersion a, ClientVersion b )
|
||||
{
|
||||
if ( IsNull( a ) && IsNull( b ) )
|
||||
return 0;
|
||||
if ( IsNull( a ) )
|
||||
return -1;
|
||||
if ( IsNull( b ) )
|
||||
return 1;
|
||||
public static int Compare(ClientVersion a, ClientVersion b)
|
||||
{
|
||||
if (IsNull(a) && IsNull(b))
|
||||
return 0;
|
||||
if (IsNull(a))
|
||||
return -1;
|
||||
if (IsNull(b))
|
||||
return 1;
|
||||
|
||||
return a.CompareTo( b );
|
||||
}
|
||||
}
|
||||
}
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,234 +24,230 @@ using Server.Network;
|
|||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public delegate void CommandEventHandler( CommandEventArgs e );
|
||||
public delegate void CommandEventHandler(CommandEventArgs e);
|
||||
|
||||
public class CommandEventArgs : EventArgs
|
||||
{
|
||||
public Mobile Mobile { get; }
|
||||
public class CommandEventArgs : EventArgs
|
||||
{
|
||||
public CommandEventArgs(Mobile mobile, string command, string argString, string[] arguments)
|
||||
{
|
||||
Mobile = mobile;
|
||||
Command = command;
|
||||
ArgString = argString;
|
||||
Arguments = arguments;
|
||||
}
|
||||
|
||||
public string Command { get; }
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public string ArgString { get; }
|
||||
public string Command{ get; }
|
||||
|
||||
public string[] Arguments { get; }
|
||||
public string ArgString{ get; }
|
||||
|
||||
public int Length => Arguments.Length;
|
||||
public string[] Arguments{ get; }
|
||||
|
||||
public string GetString( int index )
|
||||
{
|
||||
if ( index < 0 || index >= Arguments.Length )
|
||||
return "";
|
||||
public int Length => Arguments.Length;
|
||||
|
||||
return Arguments[index];
|
||||
}
|
||||
public string GetString(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return "";
|
||||
|
||||
public int GetInt32( int index )
|
||||
{
|
||||
if ( index < 0 || index >= Arguments.Length )
|
||||
return 0;
|
||||
return Arguments[index];
|
||||
}
|
||||
|
||||
return Utility.ToInt32( Arguments[index] );
|
||||
}
|
||||
public int GetInt32(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return 0;
|
||||
|
||||
public bool GetBoolean( int index )
|
||||
{
|
||||
if ( index < 0 || index >= Arguments.Length )
|
||||
return false;
|
||||
return Utility.ToInt32(Arguments[index]);
|
||||
}
|
||||
|
||||
return Utility.ToBoolean( Arguments[index] );
|
||||
}
|
||||
public bool GetBoolean(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return false;
|
||||
|
||||
public double GetDouble( int index )
|
||||
{
|
||||
if ( index < 0 || index >= Arguments.Length )
|
||||
return 0.0;
|
||||
return Utility.ToBoolean(Arguments[index]);
|
||||
}
|
||||
|
||||
return Utility.ToDouble( Arguments[index] );
|
||||
}
|
||||
public double GetDouble(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return 0.0;
|
||||
|
||||
public TimeSpan GetTimeSpan( int index )
|
||||
{
|
||||
if ( index < 0 || index >= Arguments.Length )
|
||||
return TimeSpan.Zero;
|
||||
return Utility.ToDouble(Arguments[index]);
|
||||
}
|
||||
|
||||
return Utility.ToTimeSpan( Arguments[index] );
|
||||
}
|
||||
public TimeSpan GetTimeSpan(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
public CommandEventArgs( Mobile mobile, string command, string argString, string[] arguments )
|
||||
{
|
||||
Mobile = mobile;
|
||||
Command = command;
|
||||
ArgString = argString;
|
||||
Arguments = arguments;
|
||||
}
|
||||
}
|
||||
return Utility.ToTimeSpan(Arguments[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandEntry : IComparable
|
||||
{
|
||||
public string Command { get; }
|
||||
public class CommandEntry : IComparable
|
||||
{
|
||||
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)
|
||||
{
|
||||
Command = command;
|
||||
Handler = handler;
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
|
||||
public CommandEventHandler Handler { get; }
|
||||
public string Command{ get; }
|
||||
|
||||
public AccessLevel AccessLevel { get; }
|
||||
public CommandEventHandler Handler{ get; }
|
||||
|
||||
public CommandEntry( string command, CommandEventHandler handler, AccessLevel accessLevel )
|
||||
{
|
||||
Command = command;
|
||||
Handler = handler;
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
public AccessLevel AccessLevel{ get; }
|
||||
|
||||
public int CompareTo( object obj )
|
||||
{
|
||||
if ( obj == this )
|
||||
return 0;
|
||||
if ( obj == null )
|
||||
return 1;
|
||||
public int CompareTo(object obj)
|
||||
{
|
||||
if (obj == this)
|
||||
return 0;
|
||||
if (obj == null)
|
||||
return 1;
|
||||
|
||||
if ( !(obj is CommandEntry e) )
|
||||
throw new ArgumentException();
|
||||
if (!(obj is CommandEntry e))
|
||||
throw new ArgumentException();
|
||||
|
||||
return Command.CompareTo( e.Command );
|
||||
}
|
||||
}
|
||||
return Command.CompareTo(e.Command);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CommandSystem
|
||||
{
|
||||
public static string Prefix { get; set; } = "[";
|
||||
public static class CommandSystem
|
||||
{
|
||||
static CommandSystem()
|
||||
{
|
||||
Entries = new Dictionary<string, CommandEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public static string[] Split( string value )
|
||||
{
|
||||
char[] array = value.ToCharArray();
|
||||
List<string> list = new List<string>();
|
||||
public static string Prefix{ get; set; } = "[";
|
||||
|
||||
int start = 0;
|
||||
public static Dictionary<string, CommandEntry> Entries{ get; }
|
||||
|
||||
while ( start < array.Length )
|
||||
{
|
||||
char c = array[start];
|
||||
public static AccessLevel BadCommandIgnoreLevel{ get; set; } = AccessLevel.Player;
|
||||
|
||||
if ( c == '"' )
|
||||
{
|
||||
++start;
|
||||
int end = start;
|
||||
public static string[] Split(string value)
|
||||
{
|
||||
char[] array = value.ToCharArray();
|
||||
List<string> list = new List<string>();
|
||||
|
||||
while ( end < array.Length )
|
||||
{
|
||||
if ( array[end] != '"' || array[end - 1] == '\\' )
|
||||
++end;
|
||||
else
|
||||
break;
|
||||
}
|
||||
int start = 0;
|
||||
|
||||
list.Add( value.Substring( start, end - start ) );
|
||||
while (start < array.Length)
|
||||
{
|
||||
char c = array[start];
|
||||
|
||||
start = end + 2;
|
||||
}
|
||||
else if ( c != ' ' )
|
||||
{
|
||||
int end = start;
|
||||
if (c == '"')
|
||||
{
|
||||
++start;
|
||||
int end = start;
|
||||
|
||||
while ( end < array.Length )
|
||||
{
|
||||
if ( array[end] != ' ' )
|
||||
++end;
|
||||
else
|
||||
break;
|
||||
}
|
||||
while (end < array.Length)
|
||||
if (array[end] != '"' || array[end - 1] == '\\')
|
||||
++end;
|
||||
else
|
||||
break;
|
||||
|
||||
list.Add( value.Substring( start, end - start ) );
|
||||
list.Add(value.Substring(start, end - start));
|
||||
|
||||
start = end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++start;
|
||||
}
|
||||
}
|
||||
start = end + 2;
|
||||
}
|
||||
else if (c != ' ')
|
||||
{
|
||||
int end = start;
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
while (end < array.Length)
|
||||
if (array[end] != ' ')
|
||||
++end;
|
||||
else
|
||||
break;
|
||||
|
||||
public static Dictionary<string, CommandEntry> Entries { get; }
|
||||
list.Add(value.Substring(start, end - start));
|
||||
|
||||
static CommandSystem()
|
||||
{
|
||||
Entries = new Dictionary<string, CommandEntry>( StringComparer.OrdinalIgnoreCase );
|
||||
}
|
||||
start = end + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
++start;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Register( string command, AccessLevel access, CommandEventHandler handler )
|
||||
{
|
||||
Entries[command] = new CommandEntry( command, handler, access );
|
||||
}
|
||||
return list.ToArray();
|
||||
}
|
||||
|
||||
public static AccessLevel BadCommandIgnoreLevel { get; set; } = AccessLevel.Player;
|
||||
public static void Register(string command, AccessLevel access, CommandEventHandler handler)
|
||||
{
|
||||
Entries[command] = new CommandEntry(command, handler, access);
|
||||
}
|
||||
|
||||
public static bool Handle( Mobile from, string text )
|
||||
{
|
||||
return Handle( from, text, MessageType.Regular );
|
||||
}
|
||||
public static bool Handle(Mobile from, string text)
|
||||
{
|
||||
return Handle(from, text, MessageType.Regular);
|
||||
}
|
||||
|
||||
public static bool Handle( Mobile from, string text, MessageType type )
|
||||
{
|
||||
if ( text.StartsWith( Prefix ) || type == MessageType.Command )
|
||||
{
|
||||
if ( type != MessageType.Command )
|
||||
text = text.Substring( Prefix.Length );
|
||||
public static bool Handle(Mobile from, string text, MessageType type)
|
||||
{
|
||||
if (text.StartsWith(Prefix) || type == MessageType.Command)
|
||||
{
|
||||
if (type != MessageType.Command)
|
||||
text = text.Substring(Prefix.Length);
|
||||
|
||||
int indexOf = text.IndexOf( ' ' );
|
||||
int indexOf = text.IndexOf(' ');
|
||||
|
||||
string command;
|
||||
string[] args;
|
||||
string argString;
|
||||
string command;
|
||||
string[] args;
|
||||
string argString;
|
||||
|
||||
if ( indexOf >= 0 )
|
||||
{
|
||||
argString = text.Substring( indexOf + 1 );
|
||||
if (indexOf >= 0)
|
||||
{
|
||||
argString = text.Substring(indexOf + 1);
|
||||
|
||||
command = text.Substring( 0, indexOf );
|
||||
args = Split( argString );
|
||||
}
|
||||
else
|
||||
{
|
||||
argString = "";
|
||||
command = text.ToLower();
|
||||
args = new string[0];
|
||||
}
|
||||
command = text.Substring(0, indexOf);
|
||||
args = Split(argString);
|
||||
}
|
||||
else
|
||||
{
|
||||
argString = "";
|
||||
command = text.ToLower();
|
||||
args = new string[0];
|
||||
}
|
||||
|
||||
Entries.TryGetValue( command, out CommandEntry entry );
|
||||
Entries.TryGetValue(command, out CommandEntry entry);
|
||||
|
||||
if ( entry != null )
|
||||
{
|
||||
if ( from.AccessLevel >= entry.AccessLevel )
|
||||
{
|
||||
if ( entry.Handler != null )
|
||||
{
|
||||
CommandEventArgs e = new CommandEventArgs( from, command, argString, args );
|
||||
entry.Handler( e );
|
||||
EventSink.InvokeCommand( e );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( from.AccessLevel <= BadCommandIgnoreLevel )
|
||||
return false;
|
||||
if (entry != null)
|
||||
{
|
||||
if (from.AccessLevel >= entry.AccessLevel)
|
||||
{
|
||||
if (entry.Handler != null)
|
||||
{
|
||||
CommandEventArgs e = new CommandEventArgs(from, command, argString, args);
|
||||
entry.Handler(e);
|
||||
EventSink.InvokeCommand(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
||||
return false;
|
||||
|
||||
from.SendMessage( "You do not have access to that command." );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( from.AccessLevel <= BadCommandIgnoreLevel )
|
||||
return false;
|
||||
from.SendMessage("You do not have access to that command.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
||||
return false;
|
||||
|
||||
from.SendMessage( "That is not a valid command." );
|
||||
}
|
||||
from.SendMessage("That is not a valid command.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,78 +23,69 @@ using System.Collections.Generic;
|
|||
namespace Server.ContextMenus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list of <see cref="ContextMenuEntry">entries</see> that the menu is composed of.
|
||||
/// <seealso cref="ContextMenuEntry" />
|
||||
/// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list of
|
||||
/// <see cref="ContextMenuEntry">entries</see> that the menu is composed of.
|
||||
/// <seealso cref="ContextMenuEntry" />
|
||||
/// </summary>
|
||||
public class ContextMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// </summary>
|
||||
public Mobile From { get; }
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenu instance.
|
||||
/// </summary>
|
||||
/// <param name="from">
|
||||
/// The <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// <seealso cref="From" />
|
||||
/// </param>
|
||||
/// <param name="target">
|
||||
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// <seealso cref="Target" />
|
||||
/// </param>
|
||||
public ContextMenu(Mobile from, object target)
|
||||
{
|
||||
From = from;
|
||||
Target = target;
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// </summary>
|
||||
public object Target { get; }
|
||||
List<ContextMenuEntry> list = new List<ContextMenuEntry>();
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
|
||||
/// </summary>
|
||||
public ContextMenuEntry[] Entries { get; }
|
||||
if (target is Mobile mobile)
|
||||
mobile.GetContextMenuEntries(from, list);
|
||||
else if (target is Item item) item.GetContextMenuEntries(from, list);
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenu instance.
|
||||
/// </summary>
|
||||
/// <param name="from">
|
||||
/// The <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// <seealso cref="From" />
|
||||
/// </param>
|
||||
/// <param name="target">
|
||||
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// <seealso cref="Target" />
|
||||
/// </param>
|
||||
public ContextMenu( Mobile from, object target )
|
||||
{
|
||||
From = from;
|
||||
Target = target;
|
||||
//m_Entries = (ContextMenuEntry[])list.ToArray( typeof( ContextMenuEntry ) );
|
||||
|
||||
List<ContextMenuEntry> list = new List<ContextMenuEntry>();
|
||||
Entries = list.ToArray();
|
||||
|
||||
if ( target is Mobile mobile )
|
||||
{
|
||||
mobile.GetContextMenuEntries( from, list );
|
||||
}
|
||||
else if ( target is Item item )
|
||||
{
|
||||
item.GetContextMenuEntries( from, list );
|
||||
}
|
||||
for (int i = 0; i < Entries.Length; ++i) Entries[i].Owner = this;
|
||||
}
|
||||
|
||||
//m_Entries = (ContextMenuEntry[])list.ToArray( typeof( ContextMenuEntry ) );
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// </summary>
|
||||
public Mobile From{ get; }
|
||||
|
||||
Entries = list.ToArray();
|
||||
/// <summary>
|
||||
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// </summary>
|
||||
public object Target{ get; }
|
||||
|
||||
for ( int i = 0; i < Entries.Length; ++i )
|
||||
{
|
||||
Entries[i].Owner = this;
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
|
||||
/// </summary>
|
||||
public ContextMenuEntry[] Entries{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this ContextMenu requires packet version 2.
|
||||
/// </summary>
|
||||
public bool RequiresNewPacket
|
||||
{
|
||||
get
|
||||
{
|
||||
for ( int i = 0; i < Entries.Length; ++i )
|
||||
{
|
||||
if ( Entries[i].Number < 3000000 || Entries[i].Number > 3032767 )
|
||||
return true;
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns true if this ContextMenu requires packet version 2.
|
||||
/// </summary>
|
||||
public bool RequiresNewPacket
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
if (Entries[i].Number < 3000000 || Entries[i].Number > 3032767)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,85 +23,88 @@ using Server.Network;
|
|||
namespace Server.ContextMenus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
|
||||
/// <seealso cref="ContextMenu" />
|
||||
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
|
||||
/// <seealso cref="ContextMenu" />
|
||||
/// </summary>
|
||||
public class ContextMenuEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets additional <see cref="CMEFlags">flags</see> used in client communication.
|
||||
/// </summary>
|
||||
public CMEFlags Flags { get; set; }
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (<paramref name="number" />
|
||||
/// ). No <see cref="Range">maximum range</see> is used.
|
||||
/// </summary>
|
||||
/// <param name="number">
|
||||
/// The localization number containing the name of this entry.
|
||||
/// <seealso cref="Number" />
|
||||
/// </param>
|
||||
public ContextMenuEntry(int number) : this(number, -1)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ContextMenu" /> that owns this entry.
|
||||
/// </summary>
|
||||
public ContextMenu Owner { get; set; }
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (<paramref name="number" />)
|
||||
/// and <see cref="Range">maximum range</see> (<paramref name="range" />).
|
||||
/// </summary>
|
||||
/// <param name="number">
|
||||
/// The localization number containing the name of this entry.
|
||||
/// <seealso cref="Number" />
|
||||
/// </param>
|
||||
/// <param name="range">
|
||||
/// The maximum range at which this entry can be used.
|
||||
/// <seealso cref="Range" />
|
||||
/// </param>
|
||||
public ContextMenuEntry(int number, int range)
|
||||
{
|
||||
if (number <= 0x7FFF) // Legacy code support
|
||||
Number = 3000000 + number;
|
||||
else
|
||||
Number = number;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the localization number containing the name of this entry.
|
||||
/// </summary>
|
||||
public int Number { get; set; }
|
||||
Range = range;
|
||||
Enabled = true;
|
||||
Color = 0xFFFF;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum range at which this entry may be used, in tiles. A value of -1 signifies no maximum range.
|
||||
/// </summary>
|
||||
public int Range { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets additional <see cref="CMEFlags">flags</see> used in client communication.
|
||||
/// </summary>
|
||||
public CMEFlags Flags{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the color for this entry. Format is A1-R5-G5-B5.
|
||||
/// </summary>
|
||||
public int Color { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the <see cref="ContextMenu" /> that owns this entry.
|
||||
/// </summary>
|
||||
public ContextMenu Owner{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets whether this entry is enabled. When false, the entry will appear in a gray hue and <see cref="OnClick" /> will never be invoked.
|
||||
/// </summary>
|
||||
public bool Enabled { get; set; }
|
||||
/// <summary>
|
||||
/// Gets or sets the localization number containing the name of this entry.
|
||||
/// </summary>
|
||||
public int Number{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating if non local use of this entry is permitted.
|
||||
/// </summary>
|
||||
public virtual bool NonLocalUse => false;
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum range at which this entry may be used, in tiles. A value of -1 signifies no maximum range.
|
||||
/// </summary>
|
||||
public int Range{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (<paramref name="number" />). No <see cref="Range">maximum range</see> is used.
|
||||
/// </summary>
|
||||
/// <param name="number">
|
||||
/// The localization number containing the name of this entry.
|
||||
/// <seealso cref="Number" />
|
||||
/// </param>
|
||||
public ContextMenuEntry( int number ) : this( number, -1 )
|
||||
{
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets or sets the color for this entry. Format is A1-R5-G5-B5.
|
||||
/// </summary>
|
||||
public int Color{ get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenuEntry with a given <see cref="Number">localization number</see> (<paramref name="number" />) and <see cref="Range">maximum range</see> (<paramref name="range" />).
|
||||
/// </summary>
|
||||
/// <param name="number">
|
||||
/// The localization number containing the name of this entry.
|
||||
/// <seealso cref="Number" />
|
||||
/// </param>
|
||||
/// <param name="range">
|
||||
/// The maximum range at which this entry can be used.
|
||||
/// <seealso cref="Range" />
|
||||
/// </param>
|
||||
public ContextMenuEntry( int number, int range )
|
||||
{
|
||||
if ( number <= 0x7FFF ) // Legacy code support
|
||||
Number = 3000000 + number;
|
||||
else
|
||||
Number = number;
|
||||
/// <summary>
|
||||
/// Gets or sets whether this entry is enabled. When false, the entry will appear in a gray hue and <see cref="OnClick" />
|
||||
/// will never be invoked.
|
||||
/// </summary>
|
||||
public bool Enabled{ get; set; }
|
||||
|
||||
Range = range;
|
||||
Enabled = true;
|
||||
Color = 0xFFFF;
|
||||
}
|
||||
/// <summary>
|
||||
/// Gets a value indicating if non local use of this entry is permitted.
|
||||
/// </summary>
|
||||
public virtual bool NonLocalUse => false;
|
||||
|
||||
/// <summary>
|
||||
/// Overridable. Virtual event invoked when the entry is clicked.
|
||||
/// </summary>
|
||||
public virtual void OnClick()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Overridable. Virtual event invoked when the entry is clicked.
|
||||
/// </summary>
|
||||
public virtual void OnClick()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,18 +20,18 @@
|
|||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
public class OpenBackpackEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
public class OpenBackpackEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public OpenBackpackEntry( Mobile m ) : base( 6145 )
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
public OpenBackpackEntry(Mobile m) : base(6145)
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.Use( m_Mobile.Backpack );
|
||||
}
|
||||
}
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.Use(m_Mobile.Backpack);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,19 +20,19 @@
|
|||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
public class PaperdollEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
public class PaperdollEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public PaperdollEntry( Mobile m ) : base( 6123, 18 )
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
public PaperdollEntry(Mobile m) : base(6123, 18)
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
if ( m_Mobile.CanPaperdollBeOpenedBy( Owner.From ) )
|
||||
m_Mobile.DisplayPaperdollTo( Owner.From );
|
||||
}
|
||||
}
|
||||
public override void OnClick()
|
||||
{
|
||||
if (m_Mobile.CanPaperdollBeOpenedBy(Owner.From))
|
||||
m_Mobile.DisplayPaperdollTo(Owner.From);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,67 +19,70 @@
|
|||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Diagnostics {
|
||||
public abstract class BaseProfile {
|
||||
public static void WriteAll<T>( TextWriter op, IEnumerable<T> profiles ) where T : BaseProfile {
|
||||
List<T> list = new List<T>( profiles );
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public abstract class BaseProfile
|
||||
{
|
||||
private Stopwatch _stopwatch;
|
||||
|
||||
list.Sort( delegate( T a, T b ) {
|
||||
return -a.TotalTime.CompareTo( b.TotalTime );
|
||||
} );
|
||||
protected BaseProfile(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
foreach ( T prof in list ) {
|
||||
prof.WriteTo( op );
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
_stopwatch = new Stopwatch();
|
||||
}
|
||||
|
||||
private Stopwatch _stopwatch;
|
||||
public string Name{ get; }
|
||||
|
||||
public string Name { get; }
|
||||
public long Count{ get; private set; }
|
||||
|
||||
public long Count { get; private set; }
|
||||
public TimeSpan AverageTime => TimeSpan.FromTicks(TotalTime.Ticks / Math.Max(1, Count));
|
||||
|
||||
public TimeSpan AverageTime => TimeSpan.FromTicks( TotalTime.Ticks / Math.Max( 1, Count ) );
|
||||
public TimeSpan PeakTime{ get; private set; }
|
||||
|
||||
public TimeSpan PeakTime { get; private set; }
|
||||
public TimeSpan TotalTime{ get; private set; }
|
||||
|
||||
public TimeSpan TotalTime { get; private set; }
|
||||
public static void WriteAll<T>(TextWriter op, IEnumerable<T> profiles) where T : BaseProfile
|
||||
{
|
||||
List<T> list = new List<T>(profiles);
|
||||
|
||||
protected BaseProfile( string name ) {
|
||||
Name = name;
|
||||
list.Sort(delegate(T a, T b) { return -a.TotalTime.CompareTo(b.TotalTime); });
|
||||
|
||||
_stopwatch = new Stopwatch();
|
||||
}
|
||||
foreach (T prof in list)
|
||||
{
|
||||
prof.WriteTo(op);
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void Start() {
|
||||
if ( _stopwatch.IsRunning ) {
|
||||
_stopwatch.Reset();
|
||||
}
|
||||
public virtual void Start()
|
||||
{
|
||||
if (_stopwatch.IsRunning) _stopwatch.Reset();
|
||||
|
||||
_stopwatch.Start();
|
||||
}
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
public virtual void Finish() {
|
||||
TimeSpan elapsed = _stopwatch.Elapsed;
|
||||
public virtual void Finish()
|
||||
{
|
||||
TimeSpan elapsed = _stopwatch.Elapsed;
|
||||
|
||||
TotalTime += elapsed;
|
||||
TotalTime += elapsed;
|
||||
|
||||
if ( elapsed > PeakTime ) {
|
||||
PeakTime = elapsed;
|
||||
}
|
||||
if (elapsed > PeakTime) PeakTime = elapsed;
|
||||
|
||||
Count++;
|
||||
Count++;
|
||||
|
||||
_stopwatch.Reset();
|
||||
}
|
||||
_stopwatch.Reset();
|
||||
}
|
||||
|
||||
public virtual void WriteTo( TextWriter op ) {
|
||||
op.Write( "{0,-100} {1,12:N0} {2,12:F5} {3,-12:F5} {4,12:F5}", Name, Count, AverageTime.TotalSeconds, PeakTime.TotalSeconds, TotalTime.TotalSeconds );
|
||||
}
|
||||
}
|
||||
public virtual void WriteTo(TextWriter op)
|
||||
{
|
||||
op.Write("{0,-100} {1,12:N0} {2,12:F5} {3,-12:F5} {4,12:F5}", Name, Count, AverageTime.TotalSeconds,
|
||||
PeakTime.TotalSeconds, TotalTime.TotalSeconds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,28 +21,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Diagnostics {
|
||||
public class GumpProfile : BaseProfile {
|
||||
private static Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>();
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class GumpProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>();
|
||||
|
||||
public static IEnumerable<GumpProfile> Profiles => _profiles.Values;
|
||||
public GumpProfile(Type type)
|
||||
: base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
public static GumpProfile Acquire( Type type ) {
|
||||
if ( !Core.Profiling ) {
|
||||
return null;
|
||||
}
|
||||
public static IEnumerable<GumpProfile> Profiles => _profiles.Values;
|
||||
|
||||
GumpProfile prof;
|
||||
public static GumpProfile Acquire(Type type)
|
||||
{
|
||||
if (!Core.Profiling) return null;
|
||||
|
||||
if ( !_profiles.TryGetValue( type, out prof ) ) {
|
||||
_profiles.Add( type, prof = new GumpProfile( type ) );
|
||||
}
|
||||
GumpProfile prof;
|
||||
|
||||
return prof;
|
||||
}
|
||||
if (!_profiles.TryGetValue(type, out prof)) _profiles.Add(type, prof = new GumpProfile(type));
|
||||
|
||||
public GumpProfile( Type type )
|
||||
: base( type.FullName ) {
|
||||
}
|
||||
}
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,84 +20,94 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Diagnostics {
|
||||
public abstract class BasePacketProfile : BaseProfile {
|
||||
public long TotalLength { get; private set; }
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public abstract class BasePacketProfile : BaseProfile
|
||||
{
|
||||
protected BasePacketProfile(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public double AverageLength => ( double ) TotalLength / Math.Max( 1, Count );
|
||||
public long TotalLength{ get; private set; }
|
||||
|
||||
protected BasePacketProfile(string name)
|
||||
: base( name ) {
|
||||
}
|
||||
public double AverageLength => (double)TotalLength / Math.Max(1, Count);
|
||||
|
||||
public void Finish( int length ) {
|
||||
Finish();
|
||||
public void Finish(int length)
|
||||
{
|
||||
Finish();
|
||||
|
||||
TotalLength += length;
|
||||
}
|
||||
TotalLength += length;
|
||||
}
|
||||
|
||||
public override void WriteTo( TextWriter op ) {
|
||||
base.WriteTo( op );
|
||||
public override void WriteTo(TextWriter op)
|
||||
{
|
||||
base.WriteTo(op);
|
||||
|
||||
op.Write( "\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength );
|
||||
}
|
||||
}
|
||||
op.Write("\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength);
|
||||
}
|
||||
}
|
||||
|
||||
public class PacketSendProfile : BasePacketProfile {
|
||||
private static Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>();
|
||||
public class PacketSendProfile : BasePacketProfile
|
||||
{
|
||||
private static Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>();
|
||||
|
||||
public static IEnumerable<PacketSendProfile> Profiles => _profiles.Values;
|
||||
private long _created;
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketSendProfile Acquire( Type type ) {
|
||||
PacketSendProfile prof;
|
||||
public PacketSendProfile(Type type)
|
||||
: base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
if ( !_profiles.TryGetValue( type, out prof ) ) {
|
||||
_profiles.Add( type, prof = new PacketSendProfile( type ) );
|
||||
}
|
||||
public static IEnumerable<PacketSendProfile> Profiles => _profiles.Values;
|
||||
|
||||
return prof;
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketSendProfile Acquire(Type type)
|
||||
{
|
||||
PacketSendProfile prof;
|
||||
|
||||
private long _created;
|
||||
if (!_profiles.TryGetValue(type, out prof)) _profiles.Add(type, prof = new PacketSendProfile(type));
|
||||
|
||||
public void Increment() {
|
||||
Interlocked.Increment(ref _created);
|
||||
}
|
||||
return prof;
|
||||
}
|
||||
|
||||
public PacketSendProfile( Type type )
|
||||
: base( type.FullName ) {
|
||||
}
|
||||
public void Increment()
|
||||
{
|
||||
Interlocked.Increment(ref _created);
|
||||
}
|
||||
|
||||
public override void WriteTo( TextWriter op ) {
|
||||
base.WriteTo( op );
|
||||
public override void WriteTo(TextWriter op)
|
||||
{
|
||||
base.WriteTo(op);
|
||||
|
||||
op.Write( "\t{0,12:N0}", _created );
|
||||
}
|
||||
}
|
||||
op.Write("\t{0,12:N0}", _created);
|
||||
}
|
||||
}
|
||||
|
||||
public class PacketReceiveProfile : BasePacketProfile {
|
||||
private static Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>();
|
||||
public class PacketReceiveProfile : BasePacketProfile
|
||||
{
|
||||
private static Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>();
|
||||
|
||||
public static IEnumerable<PacketReceiveProfile> Profiles => _profiles.Values;
|
||||
public PacketReceiveProfile(int packetId)
|
||||
: base($"0x{packetId:X2}")
|
||||
{
|
||||
}
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketReceiveProfile Acquire( int packetId ) {
|
||||
PacketReceiveProfile prof;
|
||||
public static IEnumerable<PacketReceiveProfile> Profiles => _profiles.Values;
|
||||
|
||||
if ( !_profiles.TryGetValue( packetId, out prof ) ) {
|
||||
_profiles.Add( packetId, prof = new PacketReceiveProfile( packetId ) );
|
||||
}
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketReceiveProfile Acquire(int packetId)
|
||||
{
|
||||
PacketReceiveProfile prof;
|
||||
|
||||
return prof;
|
||||
}
|
||||
if (!_profiles.TryGetValue(packetId, out prof))
|
||||
_profiles.Add(packetId, prof = new PacketReceiveProfile(packetId));
|
||||
|
||||
public PacketReceiveProfile( int packetId )
|
||||
: base($"0x{packetId:X2}") {
|
||||
}
|
||||
}
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,28 +21,28 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Diagnostics {
|
||||
public class TargetProfile : BaseProfile {
|
||||
private static Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>();
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class TargetProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>();
|
||||
|
||||
public static IEnumerable<TargetProfile> Profiles => _profiles.Values;
|
||||
public TargetProfile(Type type)
|
||||
: base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
public static TargetProfile Acquire( Type type ) {
|
||||
if ( !Core.Profiling ) {
|
||||
return null;
|
||||
}
|
||||
public static IEnumerable<TargetProfile> Profiles => _profiles.Values;
|
||||
|
||||
TargetProfile prof;
|
||||
public static TargetProfile Acquire(Type type)
|
||||
{
|
||||
if (!Core.Profiling) return null;
|
||||
|
||||
if ( !_profiles.TryGetValue( type, out prof ) ) {
|
||||
_profiles.Add( type, prof = new TargetProfile( type ) );
|
||||
}
|
||||
TargetProfile prof;
|
||||
|
||||
return prof;
|
||||
}
|
||||
if (!_profiles.TryGetValue(type, out prof)) _profiles.Add(type, prof = new TargetProfile(type));
|
||||
|
||||
public TargetProfile( Type type )
|
||||
: base( type.FullName ) {
|
||||
}
|
||||
}
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,40 +21,41 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Diagnostics {
|
||||
public class TimerProfile : BaseProfile {
|
||||
private static Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>();
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class TimerProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>();
|
||||
|
||||
public static IEnumerable<TimerProfile> Profiles => _profiles.Values;
|
||||
public TimerProfile(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public static TimerProfile Acquire( string name ) {
|
||||
if ( !Core.Profiling ) {
|
||||
return null;
|
||||
}
|
||||
public static IEnumerable<TimerProfile> Profiles => _profiles.Values;
|
||||
|
||||
TimerProfile prof;
|
||||
public long Created{ get; set; }
|
||||
|
||||
if ( !_profiles.TryGetValue( name, out prof ) ) {
|
||||
_profiles.Add( name, prof = new TimerProfile( name ) );
|
||||
}
|
||||
public long Started{ get; set; }
|
||||
|
||||
return prof;
|
||||
}
|
||||
public long Stopped{ get; set; }
|
||||
|
||||
public long Created { get; set; }
|
||||
public static TimerProfile Acquire(string name)
|
||||
{
|
||||
if (!Core.Profiling) return null;
|
||||
|
||||
public long Started { get; set; }
|
||||
TimerProfile prof;
|
||||
|
||||
public long Stopped { get; set; }
|
||||
if (!_profiles.TryGetValue(name, out prof)) _profiles.Add(name, prof = new TimerProfile(name));
|
||||
|
||||
public TimerProfile( string name )
|
||||
: base( name ) {
|
||||
}
|
||||
return prof;
|
||||
}
|
||||
|
||||
public override void WriteTo( TextWriter op ) {
|
||||
base.WriteTo( op );
|
||||
public override void WriteTo(TextWriter op)
|
||||
{
|
||||
base.WriteTo(op);
|
||||
|
||||
op.Write( "\t{0,12:N0} {1,12:N0} {2,-12:N0}", Created, Started, Stopped );
|
||||
}
|
||||
}
|
||||
op.Write("\t{0,12:N0} {1,12:N0} {2,-12:N0}", Created, Started, Stopped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,354 +22,396 @@ using Server.Network;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public enum EffectLayer
|
||||
{
|
||||
Head = 0,
|
||||
RightHand = 1,
|
||||
LeftHand = 2,
|
||||
Waist = 3,
|
||||
LeftFoot = 4,
|
||||
RightFoot = 5,
|
||||
CenterFeet = 7
|
||||
}
|
||||
public enum EffectLayer
|
||||
{
|
||||
Head = 0,
|
||||
RightHand = 1,
|
||||
LeftHand = 2,
|
||||
Waist = 3,
|
||||
LeftFoot = 4,
|
||||
RightFoot = 5,
|
||||
CenterFeet = 7
|
||||
}
|
||||
|
||||
public enum ParticleSupportType
|
||||
{
|
||||
Full,
|
||||
Detect,
|
||||
None
|
||||
}
|
||||
public enum ParticleSupportType
|
||||
{
|
||||
Full,
|
||||
Detect,
|
||||
None
|
||||
}
|
||||
|
||||
public static class Effects
|
||||
{
|
||||
public static ParticleSupportType ParticleSupportType{ get; set; } = ParticleSupportType.Detect;
|
||||
|
||||
public static bool SendParticlesTo(NetState state)
|
||||
{
|
||||
return ParticleSupportType == ParticleSupportType.Full ||
|
||||
ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient;
|
||||
}
|
||||
|
||||
public static void PlaySound(IPoint3D p, Map map, int soundID)
|
||||
{
|
||||
if (soundID <= -1)
|
||||
return;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(new Point3D(p));
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (playSound == null)
|
||||
playSound = Packet.Acquire(new PlaySound(soundID, p));
|
||||
|
||||
state.Send(playSound);
|
||||
}
|
||||
|
||||
Packet.Release(playSound);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e)
|
||||
{
|
||||
SendBoltEffect(e, true, 0);
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e, bool sound)
|
||||
{
|
||||
SendBoltEffect(e, sound, 0);
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e, bool sound, int hue)
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
e.ProcessDelta();
|
||||
|
||||
Packet preEffect = null, boltEffect = null, playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
if (state.Mobile.CanSee(e))
|
||||
{
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (preEffect == null)
|
||||
preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0));
|
||||
|
||||
state.Send(preEffect);
|
||||
}
|
||||
|
||||
if (boltEffect == null)
|
||||
boltEffect = Packet.Acquire(new BoltEffect(e, hue));
|
||||
|
||||
state.Send(boltEffect);
|
||||
|
||||
if (sound)
|
||||
{
|
||||
if (playSound == null)
|
||||
playSound = Packet.Acquire(new PlaySound(0x29, e));
|
||||
|
||||
state.Send(playSound);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(preEffect);
|
||||
Packet.Release(boltEffect);
|
||||
Packet.Release(playSound);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, 10, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, speed, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, 10, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed, int hue,
|
||||
int renderMode)
|
||||
{
|
||||
SendPacket(p, map, new LocationEffect(p, itemID, speed, duration, hue, renderMode));
|
||||
}
|
||||
|
||||
public static class Effects
|
||||
{
|
||||
public static ParticleSupportType ParticleSupportType { get; set; } = ParticleSupportType.Detect;
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect)
|
||||
{
|
||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, 0);
|
||||
}
|
||||
|
||||
public static bool SendParticlesTo( NetState state )
|
||||
{
|
||||
return ( ParticleSupportType == ParticleSupportType.Full || (ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient) );
|
||||
}
|
||||
|
||||
public static void PlaySound( IPoint3D p, Map map, int soundID )
|
||||
{
|
||||
if ( soundID <= -1 )
|
||||
return;
|
||||
|
||||
if ( map != null )
|
||||
{
|
||||
Packet playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange( new Point3D( p ) );
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if ( playSound == null )
|
||||
playSound = Packet.Acquire( new PlaySound( soundID, p ) );
|
||||
|
||||
state.Send( playSound );
|
||||
}
|
||||
|
||||
Packet.Release( playSound );
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendBoltEffect( IEntity e )
|
||||
{
|
||||
SendBoltEffect( e, true, 0 );
|
||||
}
|
||||
|
||||
public static void SendBoltEffect( IEntity e, bool sound )
|
||||
{
|
||||
SendBoltEffect( e, sound, 0 );
|
||||
}
|
||||
|
||||
public static void SendBoltEffect( IEntity e, bool sound, int hue )
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if ( map == null )
|
||||
return;
|
||||
|
||||
e.ProcessDelta();
|
||||
|
||||
Packet preEffect = null, boltEffect = null, playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
if ( state.Mobile.CanSee( e ) ) {
|
||||
if ( SendParticlesTo( state ) ) {
|
||||
if ( preEffect == null )
|
||||
preEffect = Packet.Acquire( new TargetParticleEffect( e, 0, 10, 5, 0, 0, 5031, 3, 0 ) );
|
||||
|
||||
state.Send( preEffect );
|
||||
}
|
||||
|
||||
if ( boltEffect == null )
|
||||
boltEffect = Packet.Acquire( new BoltEffect( e, hue ) );
|
||||
|
||||
state.Send( boltEffect );
|
||||
|
||||
if ( sound ) {
|
||||
if ( playSound == null )
|
||||
playSound = Packet.Acquire( new PlaySound( 0x29, e ) );
|
||||
|
||||
state.Send( playSound );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release( preEffect );
|
||||
Packet.Release( boltEffect );
|
||||
Packet.Release( playSound );
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration )
|
||||
{
|
||||
SendLocationEffect( p, map, itemID, duration, 10, 0, 0 );
|
||||
}
|
||||
|
||||
public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int speed )
|
||||
{
|
||||
SendLocationEffect( p, map, itemID, duration, speed, 0, 0 );
|
||||
}
|
||||
|
||||
public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode )
|
||||
{
|
||||
SendLocationEffect( p, map, itemID, duration, 10, hue, renderMode );
|
||||
}
|
||||
|
||||
public static void SendLocationEffect( IPoint3D p, Map map, int itemID, int duration, int speed, int hue, int renderMode )
|
||||
{
|
||||
SendPacket( p, map, new LocationEffect( p, itemID, speed, duration, hue, renderMode ) );
|
||||
}
|
||||
|
||||
public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int effect )
|
||||
{
|
||||
SendLocationParticles( e, itemID, speed, duration, 0, 0, effect, 0 );
|
||||
}
|
||||
|
||||
public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int effect, int unknown )
|
||||
{
|
||||
SendLocationParticles( e, itemID, speed, duration, 0, 0, effect, unknown );
|
||||
}
|
||||
|
||||
public static void SendLocationParticles( IEntity e, int itemID, int speed, int duration, int hue, int renderMode, int effect, int unknown )
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if ( map != null )
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if ( SendParticlesTo( state ) ) {
|
||||
if ( particles == null )
|
||||
particles = Packet.Acquire( new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) );
|
||||
|
||||
state.Send( particles );
|
||||
} else if ( itemID != 0 ) {
|
||||
if ( regular == null )
|
||||
regular = Packet.Acquire( new LocationEffect( e, itemID, speed, duration, hue, renderMode ) );
|
||||
|
||||
state.Send( regular );
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release( particles );
|
||||
Packet.Release( regular );
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
//SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect( IEntity target, int itemID, int duration )
|
||||
{
|
||||
SendTargetEffect( target, itemID, duration, 0, 0 );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect( IEntity target, int itemID, int speed, int duration )
|
||||
{
|
||||
SendTargetEffect( target, itemID, speed, duration, 0, 0 );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect( IEntity target, int itemID, int duration, int hue, int renderMode )
|
||||
{
|
||||
SendTargetEffect( target, itemID, 10, duration, hue, renderMode );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect( IEntity target, int itemID, int speed, int duration, int hue, int renderMode )
|
||||
{
|
||||
if ( target is Mobile mobile )
|
||||
mobile.ProcessDelta();
|
||||
|
||||
SendPacket( target.Location, target.Map, new TargetEffect( target, itemID, speed, duration, hue, renderMode ) );
|
||||
}
|
||||
|
||||
public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int effect, EffectLayer layer )
|
||||
{
|
||||
SendTargetParticles( target, itemID, speed, duration, 0, 0, effect, layer, 0 );
|
||||
}
|
||||
|
||||
public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int effect, EffectLayer layer, int unknown )
|
||||
{
|
||||
SendTargetParticles( target, itemID, speed, duration, 0, 0, effect, layer, unknown );
|
||||
}
|
||||
|
||||
public static void SendTargetParticles( IEntity target, int itemID, int speed, int duration, int hue, int renderMode, int effect, EffectLayer layer, int unknown )
|
||||
{
|
||||
if ( target is Mobile mobile )
|
||||
mobile.ProcessDelta();
|
||||
|
||||
Map map = target.Map;
|
||||
|
||||
if ( map != null )
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(target.Location);
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if ( SendParticlesTo( state ) ) {
|
||||
if ( particles == null )
|
||||
particles = Packet.Acquire( new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) );
|
||||
|
||||
state.Send( particles );
|
||||
} else if ( itemID != 0 ) {
|
||||
if ( regular == null )
|
||||
regular = Packet.Acquire( new TargetEffect( target, itemID, speed, duration, hue, renderMode ) );
|
||||
|
||||
state.Send( regular );
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release( particles );
|
||||
Packet.Release( regular );
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes )
|
||||
{
|
||||
SendMovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0 );
|
||||
}
|
||||
|
||||
public static void SendMovingEffect( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode )
|
||||
{
|
||||
if ( from is Mobile mobile )
|
||||
mobile.ProcessDelta();
|
||||
|
||||
if ( to is Mobile mobile1 )
|
||||
mobile1.ProcessDelta();
|
||||
|
||||
SendPacket( from.Location, from.Map, new MovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode ) );
|
||||
}
|
||||
|
||||
public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound )
|
||||
{
|
||||
SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, 0 );
|
||||
}
|
||||
|
||||
public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown )
|
||||
{
|
||||
SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect, explodeSound, unknown );
|
||||
}
|
||||
|
||||
public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, int unknown )
|
||||
{
|
||||
SendMovingParticles( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, (EffectLayer)255, unknown );
|
||||
}
|
||||
|
||||
public static void SendMovingParticles( IEntity from, IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, EffectLayer layer, int unknown )
|
||||
{
|
||||
if ( from is Mobile mobile )
|
||||
mobile.ProcessDelta();
|
||||
|
||||
if ( to is Mobile mobile1 )
|
||||
mobile1.ProcessDelta();
|
||||
|
||||
Map map = from.Map;
|
||||
|
||||
if ( map != null )
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(from.Location);
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if ( SendParticlesTo( state ) ) {
|
||||
if ( particles == null )
|
||||
particles = Packet.Acquire( new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer, unknown ) );
|
||||
|
||||
state.Send( particles );
|
||||
} else if ( itemID > 1 ) {
|
||||
if ( regular == null )
|
||||
regular = Packet.Acquire( new MovingEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode ) );
|
||||
|
||||
state.Send( regular );
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release( particles );
|
||||
Packet.Release( regular );
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendPacket( Point3D origin, Map map, Packet p )
|
||||
{
|
||||
if ( map != null ) {
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(origin);
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send( p );
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendPacket( IPoint3D origin, Map map, Packet p )
|
||||
{
|
||||
if ( map != null )
|
||||
{
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(new Point3D(origin));
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach ( NetState state in eable ) {
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send( p );
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect, int unknown)
|
||||
{
|
||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, unknown);
|
||||
}
|
||||
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int hue, int renderMode,
|
||||
int effect, int unknown)
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new LocationParticleEffect(e, itemID, speed, duration, hue,
|
||||
renderMode, effect, unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID != 0)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new LocationEffect(e, itemID, speed, duration, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int duration)
|
||||
{
|
||||
SendTargetEffect(target, itemID, duration, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration)
|
||||
{
|
||||
SendTargetEffect(target, itemID, speed, duration, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendTargetEffect(target, itemID, 10, duration, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue, int renderMode)
|
||||
{
|
||||
if (target is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
SendPacket(target.Location, target.Map, new TargetEffect(target, itemID, speed, duration, hue, renderMode));
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int effect,
|
||||
EffectLayer layer)
|
||||
{
|
||||
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int effect,
|
||||
EffectLayer layer, int unknown)
|
||||
{
|
||||
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, unknown);
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int hue, int renderMode,
|
||||
int effect, EffectLayer layer, int unknown)
|
||||
{
|
||||
if (target is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
Map map = target.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(target.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new TargetParticleEffect(target, itemID, speed, duration, hue,
|
||||
renderMode, effect, (int)layer, unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID != 0)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new TargetEffect(target, itemID, speed, duration, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendMovingEffect(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes)
|
||||
{
|
||||
SendMovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendMovingEffect(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue, int renderMode)
|
||||
{
|
||||
if (from is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
if (to is Mobile mobile1)
|
||||
mobile1.ProcessDelta();
|
||||
|
||||
SendPacket(from.Location, from.Map,
|
||||
new MovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode));
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect,
|
||||
explodeSound, 0);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect,
|
||||
explodeSound, unknown);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||
int unknown)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect,
|
||||
explodeEffect, explodeSound, (EffectLayer)255, unknown);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||
EffectLayer layer, int unknown)
|
||||
{
|
||||
if (from is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
if (to is Mobile mobile1)
|
||||
mobile1.ProcessDelta();
|
||||
|
||||
Map map = from.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(from.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new MovingParticleEffect(from, to, itemID, speed, duration,
|
||||
fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer,
|
||||
unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID > 1)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new MovingEffect(from, to, itemID, speed, duration, fixedDirection,
|
||||
explodes, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendPacket(Point3D origin, Map map, Packet p)
|
||||
{
|
||||
if (map != null)
|
||||
{
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(origin);
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendPacket(IPoint3D origin, Map map, Packet p)
|
||||
{
|
||||
if (map != null)
|
||||
{
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(new Point3D(origin));
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,50 +18,46 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using DiagELog = System.Diagnostics.EventLog;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class EventLog
|
||||
{
|
||||
static EventLog()
|
||||
{
|
||||
if ( !DiagELog.SourceExists( "RunUO" ) )
|
||||
{
|
||||
DiagELog.CreateEventSource( "RunUO", "Application" );
|
||||
}
|
||||
}
|
||||
public static class EventLog
|
||||
{
|
||||
static EventLog()
|
||||
{
|
||||
if (!DiagELog.SourceExists("RunUO")) DiagELog.CreateEventSource("RunUO", "Application");
|
||||
}
|
||||
|
||||
public static void Error( int eventID, string text )
|
||||
{
|
||||
DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Error, eventID );
|
||||
}
|
||||
public static void Error(int eventID, string text)
|
||||
{
|
||||
DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Error, eventID);
|
||||
}
|
||||
|
||||
public static void Error( int eventID, string format, params object[] args )
|
||||
{
|
||||
Error( eventID, string.Format( format, args ) );
|
||||
}
|
||||
public static void Error(int eventID, string format, params object[] args)
|
||||
{
|
||||
Error(eventID, string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void Warning( int eventID, string text )
|
||||
{
|
||||
DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Warning, eventID );
|
||||
}
|
||||
public static void Warning(int eventID, string text)
|
||||
{
|
||||
DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Warning, eventID);
|
||||
}
|
||||
|
||||
public static void Warning( int eventID, string format, params object[] args )
|
||||
{
|
||||
Warning( eventID, string.Format( format, args ) );
|
||||
}
|
||||
public static void Warning(int eventID, string format, params object[] args)
|
||||
{
|
||||
Warning(eventID, string.Format(format, args));
|
||||
}
|
||||
|
||||
public static void Inform( int eventID, string text )
|
||||
{
|
||||
DiagELog.WriteEntry( "RunUO", text, EventLogEntryType.Information, eventID );
|
||||
}
|
||||
public static void Inform(int eventID, string text)
|
||||
{
|
||||
DiagELog.WriteEntry("RunUO", text, EventLogEntryType.Information, eventID);
|
||||
}
|
||||
|
||||
public static void Inform( int eventID, string format, params object[] args )
|
||||
{
|
||||
Inform( eventID, string.Format( format, args ) );
|
||||
}
|
||||
}
|
||||
public static void Inform(int eventID, string format, params object[] args)
|
||||
{
|
||||
Inform(eventID, string.Format(format, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
2078
Server/EventSink.cs
2078
Server/EventSink.cs
File diff suppressed because it is too large
Load diff
|
|
@ -22,331 +22,325 @@ using System;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public enum Expansion
|
||||
{
|
||||
None,
|
||||
T2A,
|
||||
UOR,
|
||||
UOTD,
|
||||
LBR,
|
||||
AOS,
|
||||
SE,
|
||||
ML,
|
||||
SA,
|
||||
HS,
|
||||
TOL
|
||||
}
|
||||
public enum Expansion
|
||||
{
|
||||
None,
|
||||
T2A,
|
||||
UOR,
|
||||
UOTD,
|
||||
LBR,
|
||||
AOS,
|
||||
SE,
|
||||
ML,
|
||||
SA,
|
||||
HS,
|
||||
TOL
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ClientFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Felucca = 0x00000001,
|
||||
Trammel = 0x00000002,
|
||||
Ilshenar= 0x00000004,
|
||||
Malas = 0x00000008,
|
||||
Tokuno = 0x00000010,
|
||||
TerMur = 0x00000020,
|
||||
Unk1 = 0x00000040,
|
||||
Unk2 = 0x00000080,
|
||||
UOTD = 0x00000100
|
||||
}
|
||||
[Flags]
|
||||
public enum ClientFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Felucca = 0x00000001,
|
||||
Trammel = 0x00000002,
|
||||
Ilshenar = 0x00000004,
|
||||
Malas = 0x00000008,
|
||||
Tokuno = 0x00000010,
|
||||
TerMur = 0x00000020,
|
||||
Unk1 = 0x00000040,
|
||||
Unk2 = 0x00000080,
|
||||
UOTD = 0x00000100
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
T2A = 0x00000001,
|
||||
UOR = 0x00000002,
|
||||
UOTD = 0x00000004,
|
||||
LBR = 0x00000008,
|
||||
AOS = 0x00000010,
|
||||
SixthCharacterSlot = 0x00000020,
|
||||
SE = 0x00000040,
|
||||
ML = 0x00000080,
|
||||
EigthAge = 0x00000100,
|
||||
NinthAge = 0x00000200, /* Crystal/Shadow Custom House Tiles */
|
||||
TenthAge = 0x00000400,
|
||||
IncreasedStorage = 0x00000800, /* Increased Housing/Bank Storage */
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
RoleplayFaces = 0x00002000,
|
||||
TrialAccount = 0x00004000,
|
||||
LiveAccount = 0x00008000,
|
||||
SA = 0x00010000,
|
||||
HS = 0x00020000,
|
||||
Gothic = 0x00040000,
|
||||
Rustic = 0x00080000,
|
||||
Jungle = 0x00100000,
|
||||
Shadowguard = 0x00200000,
|
||||
TOL = 0x00400000,
|
||||
[Flags]
|
||||
public enum FeatureFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
T2A = 0x00000001,
|
||||
UOR = 0x00000002,
|
||||
UOTD = 0x00000004,
|
||||
LBR = 0x00000008,
|
||||
AOS = 0x00000010,
|
||||
SixthCharacterSlot = 0x00000020,
|
||||
SE = 0x00000040,
|
||||
ML = 0x00000080,
|
||||
EigthAge = 0x00000100,
|
||||
NinthAge = 0x00000200, /* Crystal/Shadow Custom House Tiles */
|
||||
TenthAge = 0x00000400,
|
||||
IncreasedStorage = 0x00000800, /* Increased Housing/Bank Storage */
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
RoleplayFaces = 0x00002000,
|
||||
TrialAccount = 0x00004000,
|
||||
LiveAccount = 0x00008000,
|
||||
SA = 0x00010000,
|
||||
HS = 0x00020000,
|
||||
Gothic = 0x00040000,
|
||||
Rustic = 0x00080000,
|
||||
Jungle = 0x00100000,
|
||||
Shadowguard = 0x00200000,
|
||||
TOL = 0x00400000,
|
||||
|
||||
ExpansionNone = None,
|
||||
ExpansionT2A = T2A,
|
||||
ExpansionUOR = ExpansionT2A | UOR,
|
||||
ExpansionUOTD = ExpansionUOR | UOTD,
|
||||
ExpansionLBR = ExpansionUOTD | LBR,
|
||||
ExpansionAOS = ExpansionLBR | AOS | LiveAccount,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML | NinthAge,
|
||||
ExpansionSA = ExpansionML | SA | Gothic | Rustic,
|
||||
ExpansionHS = ExpansionSA | HS,
|
||||
ExpansionTOL = ExpansionHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
ExpansionNone = None,
|
||||
ExpansionT2A = T2A,
|
||||
ExpansionUOR = ExpansionT2A | UOR,
|
||||
ExpansionUOTD = ExpansionUOR | UOTD,
|
||||
ExpansionLBR = ExpansionUOTD | LBR,
|
||||
ExpansionAOS = ExpansionLBR | AOS | LiveAccount,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML | NinthAge,
|
||||
ExpansionSA = ExpansionML | SA | Gothic | Rustic,
|
||||
ExpansionHS = ExpansionSA | HS,
|
||||
ExpansionTOL = ExpansionHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CharacterListFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Unk1 = 0x00000001,
|
||||
OverwriteConfigButton = 0x00000002,
|
||||
OneCharacterSlot = 0x00000004,
|
||||
ContextMenus = 0x00000008,
|
||||
SlotLimit = 0x00000010,
|
||||
AOS = 0x00000020,
|
||||
SixthCharacterSlot = 0x00000040,
|
||||
SE = 0x00000080,
|
||||
ML = 0x00000100,
|
||||
Unk2 = 0x00000200,
|
||||
UO3DClientType = 0x00000400,
|
||||
Unk3 = 0x00000800,
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
Unk4 = 0x00002000,
|
||||
NewMovementSystem = 0x00004000,
|
||||
NewFeluccaAreas = 0x00008000,
|
||||
[Flags]
|
||||
public enum CharacterListFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Unk1 = 0x00000001,
|
||||
OverwriteConfigButton = 0x00000002,
|
||||
OneCharacterSlot = 0x00000004,
|
||||
ContextMenus = 0x00000008,
|
||||
SlotLimit = 0x00000010,
|
||||
AOS = 0x00000020,
|
||||
SixthCharacterSlot = 0x00000040,
|
||||
SE = 0x00000080,
|
||||
ML = 0x00000100,
|
||||
Unk2 = 0x00000200,
|
||||
UO3DClientType = 0x00000400,
|
||||
Unk3 = 0x00000800,
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
Unk4 = 0x00002000,
|
||||
NewMovementSystem = 0x00004000,
|
||||
NewFeluccaAreas = 0x00008000,
|
||||
|
||||
ExpansionNone = ContextMenus, //
|
||||
ExpansionT2A = ContextMenus, //
|
||||
ExpansionUOR = ContextMenus, // None
|
||||
ExpansionUOTD = ContextMenus, //
|
||||
ExpansionLBR = ContextMenus, //
|
||||
ExpansionAOS = ContextMenus | AOS,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML,
|
||||
ExpansionSA = ExpansionML,
|
||||
ExpansionHS = ExpansionSA,
|
||||
ExpansionTOL = ExpansionHS
|
||||
}
|
||||
ExpansionNone = ContextMenus, //
|
||||
ExpansionT2A = ContextMenus, //
|
||||
ExpansionUOR = ContextMenus, // None
|
||||
ExpansionUOTD = ContextMenus, //
|
||||
ExpansionLBR = ContextMenus, //
|
||||
ExpansionAOS = ContextMenus | AOS,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML,
|
||||
ExpansionSA = ExpansionML,
|
||||
ExpansionHS = ExpansionSA,
|
||||
ExpansionTOL = ExpansionHS
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum HousingFlags
|
||||
{
|
||||
None = 0x0,
|
||||
AOS = 0x10,
|
||||
SE = 0x40,
|
||||
ML = 0x80,
|
||||
Crystal = 0x200,
|
||||
SA = 0x10000,
|
||||
HS = 0x20000,
|
||||
Gothic = 0x40000,
|
||||
Rustic = 0x80000,
|
||||
Jungle = 0x100000,
|
||||
Shadowguard = 0x200000,
|
||||
TOL = 0x400000,
|
||||
[Flags]
|
||||
public enum HousingFlags
|
||||
{
|
||||
None = 0x0,
|
||||
AOS = 0x10,
|
||||
SE = 0x40,
|
||||
ML = 0x80,
|
||||
Crystal = 0x200,
|
||||
SA = 0x10000,
|
||||
HS = 0x20000,
|
||||
Gothic = 0x40000,
|
||||
Rustic = 0x80000,
|
||||
Jungle = 0x100000,
|
||||
Shadowguard = 0x200000,
|
||||
TOL = 0x400000,
|
||||
|
||||
HousingAOS = AOS,
|
||||
HousingSE = HousingAOS | SE,
|
||||
HousingML = HousingSE | ML | Crystal,
|
||||
HousingSA = HousingML | SA | Gothic | Rustic,
|
||||
HousingHS = HousingSA | HS,
|
||||
HousingTOL = HousingHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
HousingAOS = AOS,
|
||||
HousingSE = HousingAOS | SE,
|
||||
HousingML = HousingSE | ML | Crystal,
|
||||
HousingSA = HousingML | SA | Gothic | Rustic,
|
||||
HousingHS = HousingSA | HS,
|
||||
HousingTOL = HousingHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
|
||||
public class ExpansionInfo
|
||||
{
|
||||
public static ExpansionInfo CoreExpansion => GetInfo(Core.Expansion);
|
||||
public class ExpansionInfo
|
||||
{
|
||||
static ExpansionInfo()
|
||||
{
|
||||
Table = new[]
|
||||
{
|
||||
new ExpansionInfo(
|
||||
0,
|
||||
"None",
|
||||
ClientFlags.None,
|
||||
FeatureFlags.ExpansionNone,
|
||||
CharacterListFlags.ExpansionNone,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
1,
|
||||
"The Second Age",
|
||||
ClientFlags.Felucca,
|
||||
FeatureFlags.ExpansionT2A,
|
||||
CharacterListFlags.ExpansionT2A,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
2,
|
||||
"Renaissance",
|
||||
ClientFlags.Trammel,
|
||||
FeatureFlags.ExpansionUOR,
|
||||
CharacterListFlags.ExpansionUOR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
3,
|
||||
"Third Dawn",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionUOTD,
|
||||
CharacterListFlags.ExpansionUOTD,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
4,
|
||||
"Blackthorn's Revenge",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionLBR,
|
||||
CharacterListFlags.ExpansionLBR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
5,
|
||||
"Age of Shadows",
|
||||
ClientFlags.Malas,
|
||||
FeatureFlags.ExpansionAOS,
|
||||
CharacterListFlags.ExpansionAOS,
|
||||
HousingFlags.HousingAOS),
|
||||
new ExpansionInfo(
|
||||
6,
|
||||
"Samurai Empire",
|
||||
ClientFlags.Tokuno,
|
||||
FeatureFlags.ExpansionSE,
|
||||
CharacterListFlags.ExpansionSE,
|
||||
HousingFlags.HousingSE),
|
||||
new ExpansionInfo(
|
||||
7,
|
||||
"Mondain's Legacy",
|
||||
new ClientVersion("5.0.0a"),
|
||||
FeatureFlags.ExpansionML,
|
||||
CharacterListFlags.ExpansionML,
|
||||
HousingFlags.HousingML),
|
||||
new ExpansionInfo(
|
||||
8,
|
||||
"Stygian Abyss",
|
||||
ClientFlags.TerMur,
|
||||
FeatureFlags.ExpansionSA,
|
||||
CharacterListFlags.ExpansionSA,
|
||||
HousingFlags.HousingSA),
|
||||
new ExpansionInfo(
|
||||
9,
|
||||
"High Seas",
|
||||
new ClientVersion("7.0.9.0"),
|
||||
FeatureFlags.ExpansionHS,
|
||||
CharacterListFlags.ExpansionHS,
|
||||
HousingFlags.HousingHS),
|
||||
new ExpansionInfo(
|
||||
10,
|
||||
"Time of Legends",
|
||||
new ClientVersion("7.0.45.65"),
|
||||
FeatureFlags.ExpansionTOL,
|
||||
CharacterListFlags.ExpansionTOL,
|
||||
HousingFlags.HousingTOL)
|
||||
};
|
||||
}
|
||||
|
||||
public static ExpansionInfo[] Table { get; private set; }
|
||||
public ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
ClientFlags clientFlags,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
|
||||
{
|
||||
ClientFlags = clientFlags;
|
||||
}
|
||||
|
||||
static ExpansionInfo()
|
||||
{
|
||||
Table = new[]
|
||||
{
|
||||
new ExpansionInfo(
|
||||
0,
|
||||
"None",
|
||||
ClientFlags.None,
|
||||
FeatureFlags.ExpansionNone,
|
||||
CharacterListFlags.ExpansionNone,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
1,
|
||||
"The Second Age",
|
||||
ClientFlags.Felucca,
|
||||
FeatureFlags.ExpansionT2A,
|
||||
CharacterListFlags.ExpansionT2A,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
2,
|
||||
"Renaissance",
|
||||
ClientFlags.Trammel,
|
||||
FeatureFlags.ExpansionUOR,
|
||||
CharacterListFlags.ExpansionUOR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
3,
|
||||
"Third Dawn",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionUOTD,
|
||||
CharacterListFlags.ExpansionUOTD,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
4,
|
||||
"Blackthorn's Revenge",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionLBR,
|
||||
CharacterListFlags.ExpansionLBR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
5,
|
||||
"Age of Shadows",
|
||||
ClientFlags.Malas,
|
||||
FeatureFlags.ExpansionAOS,
|
||||
CharacterListFlags.ExpansionAOS,
|
||||
HousingFlags.HousingAOS),
|
||||
new ExpansionInfo(
|
||||
6,
|
||||
"Samurai Empire",
|
||||
ClientFlags.Tokuno,
|
||||
FeatureFlags.ExpansionSE,
|
||||
CharacterListFlags.ExpansionSE,
|
||||
HousingFlags.HousingSE),
|
||||
new ExpansionInfo(
|
||||
7,
|
||||
"Mondain's Legacy",
|
||||
new ClientVersion("5.0.0a"),
|
||||
FeatureFlags.ExpansionML,
|
||||
CharacterListFlags.ExpansionML,
|
||||
HousingFlags.HousingML),
|
||||
new ExpansionInfo(
|
||||
8,
|
||||
"Stygian Abyss",
|
||||
ClientFlags.TerMur,
|
||||
FeatureFlags.ExpansionSA,
|
||||
CharacterListFlags.ExpansionSA,
|
||||
HousingFlags.HousingSA),
|
||||
new ExpansionInfo(
|
||||
9,
|
||||
"High Seas",
|
||||
new ClientVersion("7.0.9.0"),
|
||||
FeatureFlags.ExpansionHS,
|
||||
CharacterListFlags.ExpansionHS,
|
||||
HousingFlags.HousingHS),
|
||||
new ExpansionInfo(
|
||||
10,
|
||||
"Time of Legends",
|
||||
new ClientVersion("7.0.45.65"),
|
||||
FeatureFlags.ExpansionTOL,
|
||||
CharacterListFlags.ExpansionTOL,
|
||||
HousingFlags.HousingTOL)
|
||||
};
|
||||
}
|
||||
public ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
ClientVersion requiredClient,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
|
||||
{
|
||||
RequiredClient = requiredClient;
|
||||
}
|
||||
|
||||
public static FeatureFlags GetFeatures(Expansion ex)
|
||||
{
|
||||
var info = GetInfo(ex);
|
||||
private ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
|
||||
if (info != null)
|
||||
{
|
||||
return info.SupportedFeatures;
|
||||
}
|
||||
SupportedFeatures = supportedFeatures;
|
||||
CharacterListFlags = charListFlags;
|
||||
CustomHousingFlag = customHousingFlag;
|
||||
}
|
||||
|
||||
switch (ex)
|
||||
{
|
||||
case Expansion.None:
|
||||
return FeatureFlags.ExpansionNone;
|
||||
case Expansion.T2A:
|
||||
return FeatureFlags.ExpansionT2A;
|
||||
case Expansion.UOR:
|
||||
return FeatureFlags.ExpansionUOR;
|
||||
case Expansion.UOTD:
|
||||
return FeatureFlags.ExpansionUOTD;
|
||||
case Expansion.LBR:
|
||||
return FeatureFlags.ExpansionLBR;
|
||||
case Expansion.AOS:
|
||||
return FeatureFlags.ExpansionAOS;
|
||||
case Expansion.SE:
|
||||
return FeatureFlags.ExpansionSE;
|
||||
case Expansion.ML:
|
||||
return FeatureFlags.ExpansionML;
|
||||
case Expansion.SA:
|
||||
return FeatureFlags.ExpansionSA;
|
||||
case Expansion.HS:
|
||||
return FeatureFlags.ExpansionHS;
|
||||
case Expansion.TOL:
|
||||
return FeatureFlags.ExpansionTOL;
|
||||
}
|
||||
public static ExpansionInfo CoreExpansion => GetInfo(Core.Expansion);
|
||||
|
||||
return FeatureFlags.ExpansionNone;
|
||||
}
|
||||
public static ExpansionInfo[] Table{ get; }
|
||||
|
||||
public static ExpansionInfo GetInfo(Expansion ex)
|
||||
{
|
||||
return GetInfo((int)ex);
|
||||
}
|
||||
public int ID{ get; }
|
||||
public string Name{ get; set; }
|
||||
|
||||
public static ExpansionInfo GetInfo(int ex)
|
||||
{
|
||||
var v = ex;
|
||||
public ClientFlags ClientFlags{ get; set; }
|
||||
public FeatureFlags SupportedFeatures{ get; set; }
|
||||
public CharacterListFlags CharacterListFlags{ get; set; }
|
||||
public ClientVersion RequiredClient{ get; set; }
|
||||
public HousingFlags CustomHousingFlag{ get; set; }
|
||||
|
||||
if (v < 0 || v >= Table.Length)
|
||||
{
|
||||
v = 0;
|
||||
}
|
||||
public static FeatureFlags GetFeatures(Expansion ex)
|
||||
{
|
||||
ExpansionInfo info = GetInfo(ex);
|
||||
|
||||
return Table[v];
|
||||
}
|
||||
if (info != null) return info.SupportedFeatures;
|
||||
|
||||
public int ID { get; private set; }
|
||||
public string Name { get; set; }
|
||||
switch (ex)
|
||||
{
|
||||
case Expansion.None:
|
||||
return FeatureFlags.ExpansionNone;
|
||||
case Expansion.T2A:
|
||||
return FeatureFlags.ExpansionT2A;
|
||||
case Expansion.UOR:
|
||||
return FeatureFlags.ExpansionUOR;
|
||||
case Expansion.UOTD:
|
||||
return FeatureFlags.ExpansionUOTD;
|
||||
case Expansion.LBR:
|
||||
return FeatureFlags.ExpansionLBR;
|
||||
case Expansion.AOS:
|
||||
return FeatureFlags.ExpansionAOS;
|
||||
case Expansion.SE:
|
||||
return FeatureFlags.ExpansionSE;
|
||||
case Expansion.ML:
|
||||
return FeatureFlags.ExpansionML;
|
||||
case Expansion.SA:
|
||||
return FeatureFlags.ExpansionSA;
|
||||
case Expansion.HS:
|
||||
return FeatureFlags.ExpansionHS;
|
||||
case Expansion.TOL:
|
||||
return FeatureFlags.ExpansionTOL;
|
||||
}
|
||||
|
||||
public ClientFlags ClientFlags { get; set; }
|
||||
public FeatureFlags SupportedFeatures { get; set; }
|
||||
public CharacterListFlags CharacterListFlags { get; set; }
|
||||
public ClientVersion RequiredClient { get; set; }
|
||||
public HousingFlags CustomHousingFlag { get; set; }
|
||||
return FeatureFlags.ExpansionNone;
|
||||
}
|
||||
|
||||
public ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
ClientFlags clientFlags,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
|
||||
{
|
||||
ClientFlags = clientFlags;
|
||||
}
|
||||
public static ExpansionInfo GetInfo(Expansion ex)
|
||||
{
|
||||
return GetInfo((int)ex);
|
||||
}
|
||||
|
||||
public ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
ClientVersion requiredClient,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
|
||||
{
|
||||
RequiredClient = requiredClient;
|
||||
}
|
||||
public static ExpansionInfo GetInfo(int ex)
|
||||
{
|
||||
int v = ex;
|
||||
|
||||
private ExpansionInfo(
|
||||
int id,
|
||||
string name,
|
||||
FeatureFlags supportedFeatures,
|
||||
CharacterListFlags charListFlags,
|
||||
HousingFlags customHousingFlag)
|
||||
{
|
||||
ID = id;
|
||||
Name = name;
|
||||
if (v < 0 || v >= Table.Length) v = 0;
|
||||
|
||||
SupportedFeatures = supportedFeatures;
|
||||
CharacterListFlags = charListFlags;
|
||||
CustomHousingFlag = customHousingFlag;
|
||||
}
|
||||
return Table[v];
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
1015
Server/Geometry.cs
1015
Server/Geometry.cs
File diff suppressed because it is too large
Load diff
163
Server/Guild.cs
163
Server/Guild.cs
|
|
@ -18,113 +18,106 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Guilds
|
||||
{
|
||||
public enum GuildType
|
||||
{
|
||||
Regular,
|
||||
Chaos,
|
||||
Order
|
||||
}
|
||||
public enum GuildType
|
||||
{
|
||||
Regular,
|
||||
Chaos,
|
||||
Order
|
||||
}
|
||||
|
||||
public abstract class BaseGuild : ISerializable
|
||||
{
|
||||
protected BaseGuild( int Id )//serialization ctor
|
||||
{
|
||||
this.Id = Id;
|
||||
List.Add( this.Id, this );
|
||||
if ( this.Id+1 > m_NextID )
|
||||
m_NextID = this.Id + 1;
|
||||
}
|
||||
public abstract class BaseGuild : ISerializable
|
||||
{
|
||||
private static int m_NextID = 1;
|
||||
|
||||
protected BaseGuild()
|
||||
{
|
||||
Id = m_NextID++;
|
||||
List.Add( Id, this );
|
||||
}
|
||||
protected BaseGuild(int Id) //serialization ctor
|
||||
{
|
||||
this.Id = Id;
|
||||
List.Add(this.Id, this);
|
||||
if (this.Id + 1 > m_NextID)
|
||||
m_NextID = this.Id + 1;
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.Counselor )]
|
||||
public int Id { get; }
|
||||
protected BaseGuild()
|
||||
{
|
||||
Id = m_NextID++;
|
||||
List.Add(Id, this);
|
||||
}
|
||||
|
||||
int ISerializable.TypeReference => 0;
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Id{ get; }
|
||||
|
||||
int ISerializable.SerialIdentity => Id;
|
||||
public abstract string Abbreviation{ get; set; }
|
||||
public abstract string Name{ get; set; }
|
||||
public abstract GuildType Type{ get; set; }
|
||||
public abstract bool Disbanded{ get; }
|
||||
|
||||
public abstract void Deserialize( GenericReader reader );
|
||||
public abstract void Serialize( GenericWriter writer );
|
||||
public static Dictionary<int, BaseGuild> List{ get; } = new Dictionary<int, BaseGuild>();
|
||||
|
||||
public abstract string Abbreviation { get; set; }
|
||||
public abstract string Name { get; set; }
|
||||
public abstract GuildType Type { get; set; }
|
||||
public abstract bool Disbanded{ get; }
|
||||
public abstract void OnDelete( Mobile mob );
|
||||
int ISerializable.TypeReference => 0;
|
||||
|
||||
private static int m_NextID = 1;
|
||||
int ISerializable.SerialIdentity => Id;
|
||||
public abstract void Serialize(GenericWriter writer);
|
||||
|
||||
public static Dictionary<int, BaseGuild> List { get; } = new Dictionary<int, BaseGuild>();
|
||||
public abstract void Deserialize(GenericReader reader);
|
||||
public abstract void OnDelete(Mobile mob);
|
||||
|
||||
public static BaseGuild Find( int id )
|
||||
{
|
||||
BaseGuild g;
|
||||
public static BaseGuild Find(int id)
|
||||
{
|
||||
BaseGuild g;
|
||||
|
||||
List.TryGetValue( id, out g );
|
||||
List.TryGetValue(id, out g);
|
||||
|
||||
return g;
|
||||
}
|
||||
return g;
|
||||
}
|
||||
|
||||
public static BaseGuild FindByName( string name )
|
||||
{
|
||||
foreach ( BaseGuild g in List.Values )
|
||||
{
|
||||
if ( g.Name == name )
|
||||
return g;
|
||||
}
|
||||
public static BaseGuild FindByName(string name)
|
||||
{
|
||||
foreach (BaseGuild g in List.Values)
|
||||
if (g.Name == name)
|
||||
return g;
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BaseGuild FindByAbbrev( string abbr )
|
||||
{
|
||||
foreach ( BaseGuild g in List.Values )
|
||||
{
|
||||
if ( g.Abbreviation == abbr )
|
||||
return g;
|
||||
}
|
||||
public static BaseGuild FindByAbbrev(string abbr)
|
||||
{
|
||||
foreach (BaseGuild g in List.Values)
|
||||
if (g.Abbreviation == abbr)
|
||||
return g;
|
||||
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<BaseGuild> Search( string find )
|
||||
{
|
||||
string[] words = find.ToLower().Split( ' ' );
|
||||
List<BaseGuild> results = new List<BaseGuild>();
|
||||
public static List<BaseGuild> Search(string find)
|
||||
{
|
||||
string[] words = find.ToLower().Split(' ');
|
||||
List<BaseGuild> results = new List<BaseGuild>();
|
||||
|
||||
foreach ( BaseGuild g in List.Values )
|
||||
{
|
||||
bool match = true;
|
||||
string name = g.Name.ToLower();
|
||||
for (int i=0;i<words.Length;i++)
|
||||
{
|
||||
if ( name.IndexOf( words[i] ) == -1 )
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (BaseGuild g in List.Values)
|
||||
{
|
||||
bool match = true;
|
||||
string name = g.Name.ToLower();
|
||||
for (int i = 0; i < words.Length; i++)
|
||||
if (name.IndexOf(words[i]) == -1)
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( match )
|
||||
results.Add( g );
|
||||
}
|
||||
if (match)
|
||||
results.Add(g);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{Id:X} \"{Name} [{Abbreviation}]\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{Id:X} \"{Name} [{Abbreviation}]\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -25,372 +25,375 @@ using Server.Network;
|
|||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class Gump
|
||||
{
|
||||
private List<string> m_Strings;
|
||||
|
||||
internal int m_TextEntries, m_Switches;
|
||||
|
||||
private static int m_NextSerial = 1;
|
||||
|
||||
private int m_Serial;
|
||||
private int m_X, m_Y;
|
||||
|
||||
private bool m_Dragable = true;
|
||||
private bool m_Closable = true;
|
||||
private bool m_Resizable = true;
|
||||
private bool m_Disposable = true;
|
||||
|
||||
public static int GetTypeID( Type type )
|
||||
{
|
||||
return type.FullName.GetHashCode();
|
||||
}
|
||||
|
||||
public Gump( int x, int y )
|
||||
{
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
} while ( m_Serial == 0 ); // standard client apparently doesn't send a gump response packet if serial == 0
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
|
||||
TypeID = GetTypeID( GetType() );
|
||||
|
||||
Entries = new List<GumpEntry>();
|
||||
m_Strings = new List<string>();
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
//if ( m_Strings.Count > 0 )
|
||||
// m_Strings.Clear();
|
||||
}
|
||||
|
||||
public int TypeID { get; }
|
||||
|
||||
public List<GumpEntry> Entries { get; }
|
||||
|
||||
public int Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set
|
||||
{
|
||||
if ( m_Serial != value )
|
||||
{
|
||||
m_Serial = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set
|
||||
{
|
||||
if ( m_X != value )
|
||||
{
|
||||
m_X = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set
|
||||
{
|
||||
if ( m_Y != value )
|
||||
{
|
||||
m_Y = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Disposable
|
||||
{
|
||||
get => m_Disposable;
|
||||
set
|
||||
{
|
||||
if ( m_Disposable != value )
|
||||
{
|
||||
m_Disposable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Resizable
|
||||
{
|
||||
get => m_Resizable;
|
||||
set
|
||||
{
|
||||
if ( m_Resizable != value )
|
||||
{
|
||||
m_Resizable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Dragable
|
||||
{
|
||||
get => m_Dragable;
|
||||
set
|
||||
{
|
||||
if ( m_Dragable != value )
|
||||
{
|
||||
m_Dragable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Closable
|
||||
{
|
||||
get => m_Closable;
|
||||
set
|
||||
{
|
||||
if ( m_Closable != value )
|
||||
{
|
||||
m_Closable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void AddPage( int page )
|
||||
{
|
||||
Add( new GumpPage( page ) );
|
||||
}
|
||||
|
||||
public void AddAlphaRegion( int x, int y, int width, int height )
|
||||
{
|
||||
Add( new GumpAlphaRegion( x, y, width, height ) );
|
||||
}
|
||||
|
||||
public void AddBackground( int x, int y, int width, int height, int gumpID )
|
||||
{
|
||||
Add( new GumpBackground( x, y, width, height, gumpID ) );
|
||||
}
|
||||
|
||||
public void AddButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param )
|
||||
{
|
||||
Add( new GumpButton( x, y, normalID, pressedID, buttonID, type, param ) );
|
||||
}
|
||||
|
||||
public void AddCheck( int x, int y, int inactiveID, int activeID, bool initialState, int switchID )
|
||||
{
|
||||
Add( new GumpCheck( x, y, inactiveID, activeID, initialState, switchID ) );
|
||||
}
|
||||
|
||||
public void AddGroup( int group )
|
||||
{
|
||||
Add( new GumpGroup( group ) );
|
||||
}
|
||||
|
||||
public void AddTooltip( int number )
|
||||
{
|
||||
Add( new GumpTooltip( number ) );
|
||||
}
|
||||
|
||||
public void AddHtml( int x, int y, int width, int height, string text, bool background, bool scrollbar )
|
||||
{
|
||||
Add( new GumpHtml( x, y, width, height, text, background, scrollbar ) );
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized( int x, int y, int width, int height, int number, bool background, bool scrollbar )
|
||||
{
|
||||
Add( new GumpHtmlLocalized( x, y, width, height, number, background, scrollbar ) );
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized( int x, int y, int width, int height, int number, int color, bool background, bool scrollbar )
|
||||
{
|
||||
Add( new GumpHtmlLocalized( x, y, width, height, number, color, background, scrollbar ) );
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized( int x, int y, int width, int height, int number, string args, int color, bool background, bool scrollbar )
|
||||
{
|
||||
Add( new GumpHtmlLocalized( x, y, width, height, number, args, color, background, scrollbar ) );
|
||||
}
|
||||
|
||||
public void AddImage( int x, int y, int gumpID )
|
||||
{
|
||||
Add( new GumpImage( x, y, gumpID ) );
|
||||
}
|
||||
|
||||
public void AddImage( int x, int y, int gumpID, int hue )
|
||||
{
|
||||
Add( new GumpImage( x, y, gumpID, hue ) );
|
||||
}
|
||||
|
||||
public void AddImageTiled( int x, int y, int width, int height, int gumpID )
|
||||
{
|
||||
Add( new GumpImageTiled( x, y, width, height, gumpID ) );
|
||||
}
|
||||
|
||||
public void AddImageTiledButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height )
|
||||
{
|
||||
Add( new GumpImageTileButton( x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height ) );
|
||||
}
|
||||
public void AddImageTiledButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height, int localizedTooltip )
|
||||
{
|
||||
Add( new GumpImageTileButton( x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height, localizedTooltip ) );
|
||||
}
|
||||
|
||||
public void AddItem( int x, int y, int itemID )
|
||||
{
|
||||
Add( new GumpItem( x, y, itemID ) );
|
||||
}
|
||||
|
||||
public void AddItem( int x, int y, int itemID, int hue )
|
||||
{
|
||||
Add( new GumpItem( x, y, itemID, hue ) );
|
||||
}
|
||||
|
||||
public void AddLabel( int x, int y, int hue, string text )
|
||||
{
|
||||
Add( new GumpLabel( x, y, hue, text ) );
|
||||
}
|
||||
|
||||
public void AddLabelCropped( int x, int y, int width, int height, int hue, string text )
|
||||
{
|
||||
Add( new GumpLabelCropped( x, y, width, height, hue, text ) );
|
||||
}
|
||||
|
||||
public void AddRadio( int x, int y, int inactiveID, int activeID, bool initialState, int switchID )
|
||||
{
|
||||
Add( new GumpRadio( x, y, inactiveID, activeID, initialState, switchID ) );
|
||||
}
|
||||
|
||||
public void AddTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText )
|
||||
{
|
||||
Add( new GumpTextEntry( x, y, width, height, hue, entryID, initialText ) );
|
||||
}
|
||||
|
||||
public void AddTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText, int size ) {
|
||||
Add( new GumpTextEntryLimited( x, y, width, height, hue, entryID, initialText, size ) );
|
||||
}
|
||||
|
||||
public void AddItemProperty( int serial )
|
||||
{
|
||||
Add( new GumpItemProperty( serial ) );
|
||||
}
|
||||
|
||||
public void Add( GumpEntry g )
|
||||
{
|
||||
if ( g.Parent != this )
|
||||
{
|
||||
g.Parent = this;
|
||||
}
|
||||
else if ( !Entries.Contains( g ) )
|
||||
{
|
||||
Invalidate();
|
||||
Entries.Add( g );
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove( GumpEntry g )
|
||||
{
|
||||
if (g == null || !Entries.Contains(g))
|
||||
return;
|
||||
|
||||
Invalidate();
|
||||
Entries.Remove( g );
|
||||
g.Parent = null;
|
||||
}
|
||||
|
||||
public int Intern( string value )
|
||||
{
|
||||
int indexOf = m_Strings.IndexOf( value );
|
||||
|
||||
if ( indexOf >= 0 )
|
||||
{
|
||||
return indexOf;
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
m_Strings.Add( value );
|
||||
return m_Strings.Count - 1;
|
||||
}
|
||||
|
||||
public void SendTo( NetState state )
|
||||
{
|
||||
state.AddGump( this );
|
||||
state.Send( Compile( state ) );
|
||||
}
|
||||
|
||||
public static byte[] StringToBuffer( string str )
|
||||
{
|
||||
return Encoding.ASCII.GetBytes( str );
|
||||
}
|
||||
|
||||
private static byte[] m_BeginLayout = StringToBuffer( "{ " );
|
||||
private static byte[] m_EndLayout = StringToBuffer( " }" );
|
||||
|
||||
private static byte[] m_NoMove = StringToBuffer( "{ nomove }" );
|
||||
private static byte[] m_NoClose = StringToBuffer( "{ noclose }" );
|
||||
private static byte[] m_NoDispose = StringToBuffer( "{ nodispose }" );
|
||||
private static byte[] m_NoResize = StringToBuffer( "{ noresize }" );
|
||||
|
||||
private Packet Compile()
|
||||
{
|
||||
return Compile( null );
|
||||
}
|
||||
|
||||
private Packet Compile( NetState ns )
|
||||
{
|
||||
IGumpWriter disp;
|
||||
|
||||
if ( ns != null && ns.Unpack )
|
||||
disp = new DisplayGumpPacked( this );
|
||||
else
|
||||
disp = new DisplayGumpFast( this );
|
||||
|
||||
if ( !m_Dragable )
|
||||
disp.AppendLayout( m_NoMove );
|
||||
|
||||
if ( !m_Closable )
|
||||
disp.AppendLayout( m_NoClose );
|
||||
|
||||
if ( !m_Disposable )
|
||||
disp.AppendLayout( m_NoDispose );
|
||||
|
||||
if ( !m_Resizable )
|
||||
disp.AppendLayout( m_NoResize );
|
||||
|
||||
int count = Entries.Count;
|
||||
GumpEntry e;
|
||||
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
e = Entries[i];
|
||||
|
||||
disp.AppendLayout( m_BeginLayout );
|
||||
e.AppendTo( ns, disp );
|
||||
disp.AppendLayout( m_EndLayout );
|
||||
}
|
||||
|
||||
disp.WriteStrings( m_Strings );
|
||||
|
||||
disp.Flush();
|
||||
|
||||
m_TextEntries = disp.TextEntries;
|
||||
m_Switches = disp.Switches;
|
||||
|
||||
return disp as Packet;
|
||||
}
|
||||
|
||||
public virtual void OnResponse( NetState sender, RelayInfo info )
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnServerClose( NetState owner )
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
public class Gump
|
||||
{
|
||||
private static int m_NextSerial = 1;
|
||||
|
||||
private static byte[] m_BeginLayout = StringToBuffer("{ ");
|
||||
private static byte[] m_EndLayout = StringToBuffer(" }");
|
||||
|
||||
private static byte[] m_NoMove = StringToBuffer("{ nomove }");
|
||||
private static byte[] m_NoClose = StringToBuffer("{ noclose }");
|
||||
private static byte[] m_NoDispose = StringToBuffer("{ nodispose }");
|
||||
private static byte[] m_NoResize = StringToBuffer("{ noresize }");
|
||||
private bool m_Closable = true;
|
||||
private bool m_Disposable = true;
|
||||
|
||||
private bool m_Dragable = true;
|
||||
private bool m_Resizable = true;
|
||||
|
||||
private int m_Serial;
|
||||
private List<string> m_Strings;
|
||||
|
||||
internal int m_TextEntries, m_Switches;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public Gump(int x, int y)
|
||||
{
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
} while (m_Serial == 0); // standard client apparently doesn't send a gump response packet if serial == 0
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
|
||||
TypeID = GetTypeID(GetType());
|
||||
|
||||
Entries = new List<GumpEntry>();
|
||||
m_Strings = new List<string>();
|
||||
}
|
||||
|
||||
public int TypeID{ get; }
|
||||
|
||||
public List<GumpEntry> Entries{ get; }
|
||||
|
||||
public int Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set
|
||||
{
|
||||
if (m_Serial != value)
|
||||
{
|
||||
m_Serial = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set
|
||||
{
|
||||
if (m_X != value)
|
||||
{
|
||||
m_X = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set
|
||||
{
|
||||
if (m_Y != value)
|
||||
{
|
||||
m_Y = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Disposable
|
||||
{
|
||||
get => m_Disposable;
|
||||
set
|
||||
{
|
||||
if (m_Disposable != value)
|
||||
{
|
||||
m_Disposable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Resizable
|
||||
{
|
||||
get => m_Resizable;
|
||||
set
|
||||
{
|
||||
if (m_Resizable != value)
|
||||
{
|
||||
m_Resizable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Dragable
|
||||
{
|
||||
get => m_Dragable;
|
||||
set
|
||||
{
|
||||
if (m_Dragable != value)
|
||||
{
|
||||
m_Dragable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Closable
|
||||
{
|
||||
get => m_Closable;
|
||||
set
|
||||
{
|
||||
if (m_Closable != value)
|
||||
{
|
||||
m_Closable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTypeID(Type type)
|
||||
{
|
||||
return type.FullName.GetHashCode();
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
//if ( m_Strings.Count > 0 )
|
||||
// m_Strings.Clear();
|
||||
}
|
||||
|
||||
public void AddPage(int page)
|
||||
{
|
||||
Add(new GumpPage(page));
|
||||
}
|
||||
|
||||
public void AddAlphaRegion(int x, int y, int width, int height)
|
||||
{
|
||||
Add(new GumpAlphaRegion(x, y, width, height));
|
||||
}
|
||||
|
||||
public void AddBackground(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
Add(new GumpBackground(x, y, width, height, gumpID));
|
||||
}
|
||||
|
||||
public void AddButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param)
|
||||
{
|
||||
Add(new GumpButton(x, y, normalID, pressedID, buttonID, type, param));
|
||||
}
|
||||
|
||||
public void AddCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
Add(new GumpCheck(x, y, inactiveID, activeID, initialState, switchID));
|
||||
}
|
||||
|
||||
public void AddGroup(int group)
|
||||
{
|
||||
Add(new GumpGroup(group));
|
||||
}
|
||||
|
||||
public void AddTooltip(int number)
|
||||
{
|
||||
Add(new GumpTooltip(number));
|
||||
}
|
||||
|
||||
public void AddHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar)
|
||||
{
|
||||
Add(new GumpHtml(x, y, width, height, text, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized(int x, int y, int width, int height, int number, bool background, bool scrollbar)
|
||||
{
|
||||
Add(new GumpHtmlLocalized(x, y, width, height, number, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized(int x, int y, int width, int height, int number, int color, bool background,
|
||||
bool scrollbar)
|
||||
{
|
||||
Add(new GumpHtmlLocalized(x, y, width, height, number, color, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized(int x, int y, int width, int height, int number, string args, int color,
|
||||
bool background, bool scrollbar)
|
||||
{
|
||||
Add(new GumpHtmlLocalized(x, y, width, height, number, args, color, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddImage(int x, int y, int gumpID)
|
||||
{
|
||||
Add(new GumpImage(x, y, gumpID));
|
||||
}
|
||||
|
||||
public void AddImage(int x, int y, int gumpID, int hue)
|
||||
{
|
||||
Add(new GumpImage(x, y, gumpID, hue));
|
||||
}
|
||||
|
||||
public void AddImageTiled(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
Add(new GumpImageTiled(x, y, width, height, gumpID));
|
||||
}
|
||||
|
||||
public void AddImageTiledButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type,
|
||||
int param, int itemID, int hue, int width, int height)
|
||||
{
|
||||
Add(new GumpImageTileButton(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height));
|
||||
}
|
||||
|
||||
public void AddImageTiledButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type,
|
||||
int param, int itemID, int hue, int width, int height, int localizedTooltip)
|
||||
{
|
||||
Add(new GumpImageTileButton(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height,
|
||||
localizedTooltip));
|
||||
}
|
||||
|
||||
public void AddItem(int x, int y, int itemID)
|
||||
{
|
||||
Add(new GumpItem(x, y, itemID));
|
||||
}
|
||||
|
||||
public void AddItem(int x, int y, int itemID, int hue)
|
||||
{
|
||||
Add(new GumpItem(x, y, itemID, hue));
|
||||
}
|
||||
|
||||
public void AddLabel(int x, int y, int hue, string text)
|
||||
{
|
||||
Add(new GumpLabel(x, y, hue, text));
|
||||
}
|
||||
|
||||
public void AddLabelCropped(int x, int y, int width, int height, int hue, string text)
|
||||
{
|
||||
Add(new GumpLabelCropped(x, y, width, height, hue, text));
|
||||
}
|
||||
|
||||
public void AddRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
Add(new GumpRadio(x, y, inactiveID, activeID, initialState, switchID));
|
||||
}
|
||||
|
||||
public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText)
|
||||
{
|
||||
Add(new GumpTextEntry(x, y, width, height, hue, entryID, initialText));
|
||||
}
|
||||
|
||||
public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText, int size)
|
||||
{
|
||||
Add(new GumpTextEntryLimited(x, y, width, height, hue, entryID, initialText, size));
|
||||
}
|
||||
|
||||
public void AddItemProperty(int serial)
|
||||
{
|
||||
Add(new GumpItemProperty(serial));
|
||||
}
|
||||
|
||||
public void Add(GumpEntry g)
|
||||
{
|
||||
if (g.Parent != this)
|
||||
{
|
||||
g.Parent = this;
|
||||
}
|
||||
else if (!Entries.Contains(g))
|
||||
{
|
||||
Invalidate();
|
||||
Entries.Add(g);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(GumpEntry g)
|
||||
{
|
||||
if (g == null || !Entries.Contains(g))
|
||||
return;
|
||||
|
||||
Invalidate();
|
||||
Entries.Remove(g);
|
||||
g.Parent = null;
|
||||
}
|
||||
|
||||
public int Intern(string value)
|
||||
{
|
||||
int indexOf = m_Strings.IndexOf(value);
|
||||
|
||||
if (indexOf >= 0) return indexOf;
|
||||
|
||||
Invalidate();
|
||||
m_Strings.Add(value);
|
||||
return m_Strings.Count - 1;
|
||||
}
|
||||
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.AddGump(this);
|
||||
state.Send(Compile(state));
|
||||
}
|
||||
|
||||
public static byte[] StringToBuffer(string str)
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(str);
|
||||
}
|
||||
|
||||
private Packet Compile()
|
||||
{
|
||||
return Compile(null);
|
||||
}
|
||||
|
||||
private Packet Compile(NetState ns)
|
||||
{
|
||||
IGumpWriter disp;
|
||||
|
||||
if (ns != null && ns.Unpack)
|
||||
disp = new DisplayGumpPacked(this);
|
||||
else
|
||||
disp = new DisplayGumpFast(this);
|
||||
|
||||
if (!m_Dragable)
|
||||
disp.AppendLayout(m_NoMove);
|
||||
|
||||
if (!m_Closable)
|
||||
disp.AppendLayout(m_NoClose);
|
||||
|
||||
if (!m_Disposable)
|
||||
disp.AppendLayout(m_NoDispose);
|
||||
|
||||
if (!m_Resizable)
|
||||
disp.AppendLayout(m_NoResize);
|
||||
|
||||
int count = Entries.Count;
|
||||
GumpEntry e;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
e = Entries[i];
|
||||
|
||||
disp.AppendLayout(m_BeginLayout);
|
||||
e.AppendTo(ns, disp);
|
||||
disp.AppendLayout(m_EndLayout);
|
||||
}
|
||||
|
||||
disp.WriteStrings(m_Strings);
|
||||
|
||||
disp.Flush();
|
||||
|
||||
m_TextEntries = disp.TextEntries;
|
||||
m_Switches = disp.Switches;
|
||||
|
||||
return disp as Packet;
|
||||
}
|
||||
|
||||
public virtual void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnServerClose(NetState owner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,62 +18,60 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpAlphaRegion : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
public class GumpAlphaRegion : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("checkertrans");
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpAlphaRegion(int x, int y, int width, int height)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public GumpAlphaRegion( int x, int y, int width, int height )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ checkertrans {m_X} {m_Y} {m_Width} {m_Height} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ checkertrans {m_X} {m_Y} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "checkertrans" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,71 +18,69 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpBackground : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_GumpID;
|
||||
public class GumpBackground : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("resizepic");
|
||||
private int m_GumpID;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpBackground(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta( ref m_GumpID, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public GumpBackground( int x, int y, int width, int height, int gumpID )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ resizepic {m_X} {m_Y} {m_GumpID} {m_Width} {m_Height} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ resizepic {m_X} {m_Y} {m_GumpID} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "resizepic" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_GumpID );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,105 +18,103 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public enum GumpButtonType
|
||||
{
|
||||
Page = 0,
|
||||
Reply = 1
|
||||
}
|
||||
public enum GumpButtonType
|
||||
{
|
||||
Page = 0,
|
||||
Reply = 1
|
||||
}
|
||||
|
||||
public class GumpButton : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_ID1, m_ID2;
|
||||
private int m_ButtonID;
|
||||
private GumpButtonType m_Type;
|
||||
private int m_Param;
|
||||
public class GumpButton : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("button");
|
||||
private int m_ButtonID;
|
||||
private int m_ID1, m_ID2;
|
||||
private int m_Param;
|
||||
private GumpButtonType m_Type;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = normalID;
|
||||
m_ID2 = pressedID;
|
||||
m_ButtonID = buttonID;
|
||||
m_Type = type;
|
||||
m_Param = param;
|
||||
}
|
||||
public GumpButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = normalID;
|
||||
m_ID2 = pressedID;
|
||||
m_ButtonID = buttonID;
|
||||
m_Type = type;
|
||||
m_Param = param;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta( ref m_ID1, value );
|
||||
}
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta( ref m_ID2, value );
|
||||
}
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta( ref m_ButtonID, value );
|
||||
}
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta(ref m_ButtonID, value);
|
||||
}
|
||||
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if ( m_Type != value )
|
||||
{
|
||||
m_Type = value;
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
Gump parent = Parent;
|
||||
Gump parent = Parent;
|
||||
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta( ref m_Param, value );
|
||||
}
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta(ref m_Param, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ button {m_X} {m_Y} {m_ID1} {m_ID2} {(int) m_Type} {m_Param} {m_ButtonID} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ button {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "button" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_ID1 );
|
||||
disp.AppendLayout( m_ID2 );
|
||||
disp.AppendLayout( (int)m_Type );
|
||||
disp.AppendLayout( m_Param );
|
||||
disp.AppendLayout( m_ButtonID );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout((int)m_Type);
|
||||
disp.AppendLayout(m_Param);
|
||||
disp.AppendLayout(m_ButtonID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,82 +18,80 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpCheck : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
public class GumpCheck : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("checkbox");
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta( ref m_ID1, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta( ref m_ID2, value );
|
||||
}
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta( ref m_InitialState, value );
|
||||
}
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta( ref m_SwitchID, value );
|
||||
}
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta(ref m_InitialState, value);
|
||||
}
|
||||
|
||||
public GumpCheck( int x, int y, int inactiveID, int activeID, bool initialState, int switchID )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta(ref m_SwitchID, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ checkbox {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ checkbox {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "checkbox" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout(m_InitialState);
|
||||
disp.AppendLayout(m_SwitchID);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_ID1 );
|
||||
disp.AppendLayout( m_ID2 );
|
||||
disp.AppendLayout( m_InitialState );
|
||||
disp.AppendLayout( m_SwitchID );
|
||||
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,63 +22,47 @@ using Server.Network;
|
|||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public abstract class GumpEntry
|
||||
{
|
||||
private Gump m_Parent;
|
||||
public abstract class GumpEntry
|
||||
{
|
||||
private Gump m_Parent;
|
||||
|
||||
protected GumpEntry()
|
||||
{
|
||||
}
|
||||
public Gump Parent
|
||||
{
|
||||
get => m_Parent;
|
||||
set
|
||||
{
|
||||
if (m_Parent != value)
|
||||
{
|
||||
m_Parent?.Remove(this);
|
||||
|
||||
protected void Delta( ref int var, int val )
|
||||
{
|
||||
if ( var != val )
|
||||
{
|
||||
var = val;
|
||||
}
|
||||
}
|
||||
m_Parent = value;
|
||||
|
||||
protected void Delta( ref bool var, bool val )
|
||||
{
|
||||
if ( var != val )
|
||||
{
|
||||
var = val;
|
||||
}
|
||||
}
|
||||
m_Parent?.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void Delta( ref string var, string val )
|
||||
{
|
||||
if ( var != val )
|
||||
{
|
||||
var = val;
|
||||
}
|
||||
}
|
||||
protected void Delta(ref int var, int val)
|
||||
{
|
||||
if (var != val) var = val;
|
||||
}
|
||||
|
||||
protected void Delta( ref object[] var, object[] val )
|
||||
{
|
||||
if ( var != val )
|
||||
{
|
||||
var = val;
|
||||
}
|
||||
}
|
||||
protected void Delta(ref bool var, bool val)
|
||||
{
|
||||
if (var != val) var = val;
|
||||
}
|
||||
|
||||
public Gump Parent
|
||||
{
|
||||
get => m_Parent;
|
||||
set
|
||||
{
|
||||
if ( m_Parent != value )
|
||||
{
|
||||
m_Parent?.Remove( this );
|
||||
protected void Delta(ref string var, string val)
|
||||
{
|
||||
if (var != val) var = val;
|
||||
}
|
||||
|
||||
m_Parent = value;
|
||||
protected void Delta(ref object[] var, object[] val)
|
||||
{
|
||||
if (var != val) var = val;
|
||||
}
|
||||
|
||||
m_Parent?.Add( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract string Compile( NetState ns );
|
||||
public abstract void AppendTo( NetState ns, IGumpWriter disp );
|
||||
}
|
||||
public abstract string Compile(NetState ns);
|
||||
public abstract void AppendTo(NetState ns, IGumpWriter disp);
|
||||
}
|
||||
}
|
||||
|
|
@ -18,37 +18,35 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpGroup : GumpEntry
|
||||
{
|
||||
private int m_Group;
|
||||
public class GumpGroup : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("group");
|
||||
private int m_Group;
|
||||
|
||||
public GumpGroup( int group )
|
||||
{
|
||||
m_Group = group;
|
||||
}
|
||||
public GumpGroup(int group)
|
||||
{
|
||||
m_Group = group;
|
||||
}
|
||||
|
||||
public int Group
|
||||
{
|
||||
get => m_Group;
|
||||
set => Delta( ref m_Group, value );
|
||||
}
|
||||
public int Group
|
||||
{
|
||||
get => m_Group;
|
||||
set => Delta(ref m_Group, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ group {m_Group} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ group {m_Group} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "group" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_Group );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Group);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,89 +18,87 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpHtml : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private string m_Text;
|
||||
private bool m_Background, m_Scrollbar;
|
||||
public class GumpHtml : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump");
|
||||
private bool m_Background, m_Scrollbar;
|
||||
private string m_Text;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Text = text;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta( ref m_Text, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta( ref m_Background, value );
|
||||
}
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta( ref m_Scrollbar, value );
|
||||
}
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta(ref m_Background, value);
|
||||
}
|
||||
|
||||
public GumpHtml( int x, int y, int width, int height, string text, bool background, bool scrollbar )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Text = text;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
}
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta(ref m_Scrollbar, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return
|
||||
$"{{ htmlgump {m_X} {m_Y} {m_Width} {m_Height} {Parent.Intern(m_Text)} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ htmlgump {m_X} {m_Y} {m_Width} {m_Height} {Parent.Intern(m_Text)} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "htmlgump" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( Parent.Intern( m_Text ) );
|
||||
disp.AppendLayout( m_Background );
|
||||
disp.AppendLayout( m_Scrollbar );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,215 +18,214 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public enum GumpHtmlLocalizedType
|
||||
{
|
||||
Plain,
|
||||
Color,
|
||||
Args
|
||||
}
|
||||
public enum GumpHtmlLocalizedType
|
||||
{
|
||||
Plain,
|
||||
Color,
|
||||
Args
|
||||
}
|
||||
|
||||
public class GumpHtmlLocalized : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_Number;
|
||||
private string m_Args;
|
||||
private int m_Color;
|
||||
private bool m_Background, m_Scrollbar;
|
||||
public class GumpHtmlLocalized : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump");
|
||||
private static byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor");
|
||||
private static byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok");
|
||||
private string m_Args;
|
||||
private bool m_Background, m_Scrollbar;
|
||||
private int m_Color;
|
||||
private int m_Number;
|
||||
|
||||
private GumpHtmlLocalizedType m_Type;
|
||||
private GumpHtmlLocalizedType m_Type;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpHtmlLocalized(int x, int y, int width, int height, int number, bool background, bool scrollbar)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
m_Type = GumpHtmlLocalizedType.Plain;
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public GumpHtmlLocalized(int x, int y, int width, int height, int number, int color, bool background, bool scrollbar)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Color = color;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
m_Type = GumpHtmlLocalizedType.Color;
|
||||
}
|
||||
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta( ref m_Number, value );
|
||||
}
|
||||
public GumpHtmlLocalized(int x, int y, int width, int height, int number, string args, int color, bool background,
|
||||
bool scrollbar)
|
||||
{
|
||||
// Are multiple arguments unsupported? And what about non ASCII arguments?
|
||||
|
||||
public string Args
|
||||
{
|
||||
get => m_Args;
|
||||
set => Delta( ref m_Args, value );
|
||||
}
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Args = args;
|
||||
m_Color = color;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
|
||||
public int Color
|
||||
{
|
||||
get => m_Color;
|
||||
set => Delta( ref m_Color, value );
|
||||
}
|
||||
m_Type = GumpHtmlLocalizedType.Args;
|
||||
}
|
||||
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta( ref m_Background, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta( ref m_Scrollbar, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public GumpHtmlLocalizedType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if ( m_Type != value )
|
||||
{
|
||||
m_Type = value;
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
Parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public GumpHtmlLocalized( int x, int y, int width, int height, int number, bool background, bool scrollbar )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta(ref m_Number, value);
|
||||
}
|
||||
|
||||
m_Type = GumpHtmlLocalizedType.Plain;
|
||||
}
|
||||
public string Args
|
||||
{
|
||||
get => m_Args;
|
||||
set => Delta(ref m_Args, value);
|
||||
}
|
||||
|
||||
public GumpHtmlLocalized( int x, int y, int width, int height, int number, int color, bool background, bool scrollbar )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Color = color;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
public int Color
|
||||
{
|
||||
get => m_Color;
|
||||
set => Delta(ref m_Color, value);
|
||||
}
|
||||
|
||||
m_Type = GumpHtmlLocalizedType.Color;
|
||||
}
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta(ref m_Background, value);
|
||||
}
|
||||
|
||||
public GumpHtmlLocalized( int x, int y, int width, int height, int number, string args, int color, bool background, bool scrollbar )
|
||||
{
|
||||
// Are multiple arguments unsupported? And what about non ASCII arguments?
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta(ref m_Scrollbar, value);
|
||||
}
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Number = number;
|
||||
m_Args = args;
|
||||
m_Color = color;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
public GumpHtmlLocalizedType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
m_Type = GumpHtmlLocalizedType.Args;
|
||||
}
|
||||
Parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
switch ( m_Type )
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
return
|
||||
$"{{ xmfhtmlgump {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
switch (m_Type)
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
return
|
||||
$"{{ xmfhtmlgump {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
|
||||
case GumpHtmlLocalizedType.Color:
|
||||
return
|
||||
$"{{ xmfhtmlgumpcolor {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} }}";
|
||||
case GumpHtmlLocalizedType.Color:
|
||||
return
|
||||
$"{{ xmfhtmlgumpcolor {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} }}";
|
||||
|
||||
default: // GumpHtmlLocalizedType.Args
|
||||
return
|
||||
$"{{ xmfhtmltok {m_X} {m_Y} {m_Width} {m_Height} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} {m_Number} @{m_Args}@ }}";
|
||||
}
|
||||
}
|
||||
default: // GumpHtmlLocalizedType.Args
|
||||
return
|
||||
$"{{ xmfhtmltok {m_X} {m_Y} {m_Width} {m_Height} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} {m_Number} @{m_Args}@ }}";
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutNamePlain = Gump.StringToBuffer( "xmfhtmlgump" );
|
||||
private static byte[] m_LayoutNameColor = Gump.StringToBuffer( "xmfhtmlgumpcolor" );
|
||||
private static byte[] m_LayoutNameArgs = Gump.StringToBuffer( "xmfhtmltok" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
switch (m_Type)
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
{
|
||||
disp.AppendLayout(m_LayoutNamePlain);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
switch ( m_Type )
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
{
|
||||
disp.AppendLayout( m_LayoutNamePlain );
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Number);
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Number );
|
||||
disp.AppendLayout( m_Background );
|
||||
disp.AppendLayout( m_Scrollbar );
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GumpHtmlLocalizedType.Color:
|
||||
{
|
||||
disp.AppendLayout(m_LayoutNameColor);
|
||||
|
||||
case GumpHtmlLocalizedType.Color:
|
||||
{
|
||||
disp.AppendLayout( m_LayoutNameColor );
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Number);
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
disp.AppendLayout(m_Color);
|
||||
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Number );
|
||||
disp.AppendLayout( m_Background );
|
||||
disp.AppendLayout( m_Scrollbar );
|
||||
disp.AppendLayout( m_Color );
|
||||
break;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case GumpHtmlLocalizedType.Args:
|
||||
{
|
||||
disp.AppendLayout(m_LayoutNameArgs);
|
||||
|
||||
case GumpHtmlLocalizedType.Args:
|
||||
{
|
||||
disp.AppendLayout( m_LayoutNameArgs );
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
disp.AppendLayout(m_Color);
|
||||
disp.AppendLayout(m_Number);
|
||||
disp.AppendLayout(m_Args);
|
||||
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Background );
|
||||
disp.AppendLayout( m_Scrollbar );
|
||||
disp.AppendLayout( m_Color );
|
||||
disp.AppendLayout( m_Number );
|
||||
disp.AppendLayout( m_Args );
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,75 +18,73 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImage : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_GumpID;
|
||||
private int m_Hue;
|
||||
public class GumpImage : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppic");
|
||||
private static byte[] m_HueEquals = Gump.StringToBuffer(" hue=");
|
||||
private int m_GumpID;
|
||||
private int m_Hue;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpImage( int x, int y, int gumpID ) : this( x, y, gumpID, 0 )
|
||||
{
|
||||
}
|
||||
public GumpImage(int x, int y, int gumpID) : this(x, y, gumpID, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public GumpImage( int x, int y, int gumpID, int hue )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_GumpID = gumpID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
public GumpImage(int x, int y, int gumpID, int hue)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_GumpID = gumpID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta( ref m_GumpID, value );
|
||||
}
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
if ( m_Hue == 0 )
|
||||
return $"{{ gumppic {m_X} {m_Y} {m_GumpID} }}";
|
||||
return $"{{ gumppic {m_X} {m_Y} {m_GumpID} hue={m_Hue} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
if (m_Hue == 0)
|
||||
return $"{{ gumppic {m_X} {m_Y} {m_GumpID} }}";
|
||||
return $"{{ gumppic {m_X} {m_Y} {m_GumpID} hue={m_Hue} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppic" );
|
||||
private static byte[] m_HueEquals = Gump.StringToBuffer( " hue=" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_GumpID );
|
||||
|
||||
if ( m_Hue != 0 )
|
||||
{
|
||||
disp.AppendLayout( m_HueEquals );
|
||||
disp.AppendLayoutNS( m_Hue );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (m_Hue != 0)
|
||||
{
|
||||
disp.AppendLayout(m_HueEquals);
|
||||
disp.AppendLayoutNS(m_Hue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,157 +18,161 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImageTileButton : GumpEntry
|
||||
{
|
||||
//Note, on OSI, The tooltip supports ONLY clilocs as far as I can figure out, and the tooltip ONLY works after the buttonTileArt (as far as I can tell from testing)
|
||||
private int m_X, m_Y;
|
||||
private int m_ID1, m_ID2;
|
||||
private int m_ButtonID;
|
||||
private GumpButtonType m_Type;
|
||||
private int m_Param;
|
||||
public class GumpImageTileButton : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("buttontileart");
|
||||
private static byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip");
|
||||
private int m_ButtonID;
|
||||
private int m_Height;
|
||||
private int m_Hue;
|
||||
private int m_ID1, m_ID2;
|
||||
|
||||
private int m_ItemID;
|
||||
private int m_Hue;
|
||||
private int m_Width;
|
||||
private int m_Height;
|
||||
private int m_ItemID;
|
||||
private int m_Param;
|
||||
private GumpButtonType m_Type;
|
||||
|
||||
public GumpImageTileButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height ) : this(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height, -1 )
|
||||
{
|
||||
}
|
||||
public GumpImageTileButton( int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param, int itemID, int hue, int width, int height, int localizedTooltip )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = normalID;
|
||||
m_ID2 = pressedID;
|
||||
m_ButtonID = buttonID;
|
||||
m_Type = type;
|
||||
m_Param = param;
|
||||
private int m_Width;
|
||||
|
||||
m_ItemID = itemID;
|
||||
m_Hue = hue;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
//Note, on OSI, The tooltip supports ONLY clilocs as far as I can figure out, and the tooltip ONLY works after the buttonTileArt (as far as I can tell from testing)
|
||||
private int m_X, m_Y;
|
||||
|
||||
LocalizedTooltip = localizedTooltip;
|
||||
}
|
||||
public GumpImageTileButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param,
|
||||
int itemID, int hue, int width, int height) : this(x, y, normalID, pressedID, buttonID, type, param, itemID, hue,
|
||||
width, height, -1)
|
||||
{
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpImageTileButton(int x, int y, int normalID, int pressedID, int buttonID, GumpButtonType type, int param,
|
||||
int itemID, int hue, int width, int height, int localizedTooltip)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = normalID;
|
||||
m_ID2 = pressedID;
|
||||
m_ButtonID = buttonID;
|
||||
m_Type = type;
|
||||
m_Param = param;
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
m_ItemID = itemID;
|
||||
m_Hue = hue;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta( ref m_ID1, value );
|
||||
}
|
||||
LocalizedTooltip = localizedTooltip;
|
||||
}
|
||||
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta( ref m_ID2, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta( ref m_ButtonID, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if ( m_Type != value )
|
||||
{
|
||||
m_Type = value;
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
Gump parent = Parent;
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta(ref m_ButtonID, value);
|
||||
}
|
||||
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta( ref m_Param, value );
|
||||
}
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta( ref m_ItemID, value );
|
||||
}
|
||||
Gump parent = Parent;
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta(ref m_Param, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta(ref m_ItemID, value);
|
||||
}
|
||||
|
||||
public int LocalizedTooltip { get; set; }
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
if ( LocalizedTooltip > 0 )
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int) m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}{{ tooltip {LocalizedTooltip} }}";
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int) m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}";
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "buttontileart" );
|
||||
private static byte[] m_LayoutTooltip = Gump.StringToBuffer( " }{ tooltip" );
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_ID1 );
|
||||
disp.AppendLayout( m_ID2 );
|
||||
disp.AppendLayout( (int)m_Type );
|
||||
disp.AppendLayout( m_Param );
|
||||
disp.AppendLayout( m_ButtonID );
|
||||
public int LocalizedTooltip{ get; set; }
|
||||
|
||||
disp.AppendLayout( m_ItemID );
|
||||
disp.AppendLayout( m_Hue );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
if (LocalizedTooltip > 0)
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}{{ tooltip {LocalizedTooltip} }}";
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
if ( LocalizedTooltip > 0 )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutTooltip );
|
||||
disp.AppendLayout( LocalizedTooltip );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout((int)m_Type);
|
||||
disp.AppendLayout(m_Param);
|
||||
disp.AppendLayout(m_ButtonID);
|
||||
|
||||
disp.AppendLayout(m_ItemID);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
|
||||
if (LocalizedTooltip > 0)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutTooltip);
|
||||
disp.AppendLayout(LocalizedTooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,71 +18,69 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImageTiled : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_GumpID;
|
||||
public class GumpImageTiled : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled");
|
||||
private int m_GumpID;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpImageTiled( int x, int y, int width, int height, int gumpID )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
public GumpImageTiled(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta( ref m_GumpID, value );
|
||||
}
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ gumppictiled {m_X} {m_Y} {m_Width} {m_Height} {m_GumpID} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ gumppictiled {m_X} {m_Y} {m_Width} {m_Height} {m_GumpID} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppictiled" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_GumpID );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,72 +18,70 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpItem : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_ItemID;
|
||||
private int m_Hue;
|
||||
public class GumpItem : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("tilepic");
|
||||
private static byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue");
|
||||
private int m_Hue;
|
||||
private int m_ItemID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpItem( int x, int y, int itemID ) : this( x, y, itemID, 0 )
|
||||
{
|
||||
}
|
||||
public GumpItem(int x, int y, int itemID) : this(x, y, itemID, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public GumpItem( int x, int y, int itemID, int hue )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ItemID = itemID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
public GumpItem(int x, int y, int itemID, int hue)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ItemID = itemID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta( ref m_ItemID, value );
|
||||
}
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta(ref m_ItemID, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
if ( m_Hue == 0 )
|
||||
return $"{{ tilepic {m_X} {m_Y} {m_ItemID} }}";
|
||||
return $"{{ tilepichue {m_X} {m_Y} {m_ItemID} {m_Hue} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
if (m_Hue == 0)
|
||||
return $"{{ tilepic {m_X} {m_Y} {m_ItemID} }}";
|
||||
return $"{{ tilepichue {m_X} {m_Y} {m_ItemID} {m_Hue} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "tilepic" );
|
||||
private static byte[] m_LayoutNameHue = Gump.StringToBuffer( "tilepichue" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_Hue == 0 ? m_LayoutName : m_LayoutNameHue);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ItemID);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_Hue == 0 ? m_LayoutName : m_LayoutNameHue );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_ItemID );
|
||||
|
||||
if ( m_Hue != 0 )
|
||||
disp.AppendLayout( m_Hue );
|
||||
}
|
||||
}
|
||||
if (m_Hue != 0)
|
||||
disp.AppendLayout(m_Hue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,37 +18,35 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpItemProperty : GumpEntry
|
||||
{
|
||||
private int m_Serial;
|
||||
public class GumpItemProperty : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty");
|
||||
private int m_Serial;
|
||||
|
||||
public GumpItemProperty( int serial )
|
||||
{
|
||||
m_Serial = serial;
|
||||
}
|
||||
public GumpItemProperty(int serial)
|
||||
{
|
||||
m_Serial = serial;
|
||||
}
|
||||
|
||||
public int Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set => Delta( ref m_Serial, value );
|
||||
}
|
||||
public int Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set => Delta(ref m_Serial, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ itemproperty {m_Serial} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ itemproperty {m_Serial} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "itemproperty" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_Serial );
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,63 +18,61 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpLabel : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
public class GumpLabel : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("text");
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpLabel( int x, int y, int hue, string text )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
public GumpLabel(int x, int y, int hue, string text)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta( ref m_Text, value );
|
||||
}
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ text {m_X} {m_Y} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ text {m_X} {m_Y} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "text" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Hue );
|
||||
disp.AppendLayout( Parent.Intern( m_Text ) );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,80 +18,78 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpLabelCropped : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
public class GumpLabelCropped : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("croppedtext");
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpLabelCropped(int x, int y, int width, int height, int hue, string text)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta( ref m_Text, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public GumpLabelCropped( int x, int y, int width, int height, int hue, string text )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ croppedtext {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ croppedtext {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "croppedtext" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Hue );
|
||||
disp.AppendLayout( Parent.Intern( m_Text ) );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,37 +18,35 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpPage : GumpEntry
|
||||
{
|
||||
private int m_Page;
|
||||
public class GumpPage : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("page");
|
||||
private int m_Page;
|
||||
|
||||
public GumpPage( int page )
|
||||
{
|
||||
m_Page = page;
|
||||
}
|
||||
public GumpPage(int page)
|
||||
{
|
||||
m_Page = page;
|
||||
}
|
||||
|
||||
public int Page
|
||||
{
|
||||
get => m_Page;
|
||||
set => Delta( ref m_Page, value );
|
||||
}
|
||||
public int Page
|
||||
{
|
||||
get => m_Page;
|
||||
set => Delta(ref m_Page, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ page {m_Page} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ page {m_Page} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "page" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_Page );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Page);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,82 +18,80 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpRadio : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
public class GumpRadio : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("radio");
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta( ref m_ID1, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta( ref m_ID2, value );
|
||||
}
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta( ref m_InitialState, value );
|
||||
}
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta( ref m_SwitchID, value );
|
||||
}
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta(ref m_InitialState, value);
|
||||
}
|
||||
|
||||
public GumpRadio( int x, int y, int inactiveID, int activeID, bool initialState, int switchID )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta(ref m_SwitchID, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ radio {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ radio {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "radio" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout(m_InitialState);
|
||||
disp.AppendLayout(m_SwitchID);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_ID1 );
|
||||
disp.AppendLayout( m_ID2 );
|
||||
disp.AppendLayout( m_InitialState );
|
||||
disp.AppendLayout( m_SwitchID );
|
||||
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,92 +18,90 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTextEntry : GumpEntry
|
||||
{
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_Hue;
|
||||
private int m_EntryID;
|
||||
private string m_InitialText;
|
||||
public class GumpTextEntry : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("textentry");
|
||||
private int m_EntryID;
|
||||
private int m_Hue;
|
||||
private string m_InitialText;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int EntryID
|
||||
{
|
||||
get => m_EntryID;
|
||||
set => Delta( ref m_EntryID, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public string InitialText
|
||||
{
|
||||
get => m_InitialText;
|
||||
set => Delta( ref m_InitialText, value );
|
||||
}
|
||||
public int EntryID
|
||||
{
|
||||
get => m_EntryID;
|
||||
set => Delta(ref m_EntryID, value);
|
||||
}
|
||||
|
||||
public GumpTextEntry( int x, int y, int width, int height, int hue, int entryID, string initialText )
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
}
|
||||
public string InitialText
|
||||
{
|
||||
get => m_InitialText;
|
||||
set => Delta(ref m_InitialText, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return
|
||||
$"{{ textentry {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ textentry {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "textentry" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_EntryID);
|
||||
disp.AppendLayout(Parent.Intern(m_InitialText));
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Hue );
|
||||
disp.AppendLayout( m_EntryID );
|
||||
disp.AppendLayout( Parent.Intern( m_InitialText ) );
|
||||
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,88 +18,99 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps {
|
||||
public class GumpTextEntryLimited : GumpEntry {
|
||||
private int m_X, m_Y;
|
||||
private int m_Width, m_Height;
|
||||
private int m_Hue;
|
||||
private int m_EntryID;
|
||||
private string m_InitialText;
|
||||
private int m_Size;
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTextEntryLimited : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited");
|
||||
private int m_EntryID;
|
||||
private int m_Hue;
|
||||
private string m_InitialText;
|
||||
private int m_Size;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public int X {
|
||||
get => m_X;
|
||||
set => Delta( ref m_X, value );
|
||||
}
|
||||
public GumpTextEntryLimited(int x, int y, int width, int height, int hue, int entryID, string initialText, int size)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
m_Size = size;
|
||||
}
|
||||
|
||||
public int Y {
|
||||
get => m_Y;
|
||||
set => Delta( ref m_Y, value );
|
||||
}
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Width {
|
||||
get => m_Width;
|
||||
set => Delta( ref m_Width, value );
|
||||
}
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Height {
|
||||
get => m_Height;
|
||||
set => Delta( ref m_Height, value );
|
||||
}
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Hue {
|
||||
get => m_Hue;
|
||||
set => Delta( ref m_Hue, value );
|
||||
}
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int EntryID {
|
||||
get => m_EntryID;
|
||||
set => Delta( ref m_EntryID, value );
|
||||
}
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public string InitialText {
|
||||
get => m_InitialText;
|
||||
set => Delta( ref m_InitialText, value );
|
||||
}
|
||||
public int EntryID
|
||||
{
|
||||
get => m_EntryID;
|
||||
set => Delta(ref m_EntryID, value);
|
||||
}
|
||||
|
||||
public int Size {
|
||||
get => m_Size;
|
||||
set => Delta( ref m_Size, value );
|
||||
}
|
||||
public string InitialText
|
||||
{
|
||||
get => m_InitialText;
|
||||
set => Delta(ref m_InitialText, value);
|
||||
}
|
||||
|
||||
public GumpTextEntryLimited( int x, int y, int width, int height, int hue, int entryID, string initialText, int size ) {
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
m_Size = size;
|
||||
}
|
||||
public int Size
|
||||
{
|
||||
get => m_Size;
|
||||
set => Delta(ref m_Size, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns ) {
|
||||
return
|
||||
$"{{ textentrylimited {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} {m_Size} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ textentrylimited {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} {m_Size} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "textentrylimited" );
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_EntryID);
|
||||
disp.AppendLayout(Parent.Intern(m_InitialText));
|
||||
disp.AppendLayout(m_Size);
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp ) {
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_X );
|
||||
disp.AppendLayout( m_Y );
|
||||
disp.AppendLayout( m_Width );
|
||||
disp.AppendLayout( m_Height );
|
||||
disp.AppendLayout( m_Hue );
|
||||
disp.AppendLayout( m_EntryID );
|
||||
disp.AppendLayout( Parent.Intern( m_InitialText ) );
|
||||
disp.AppendLayout( m_Size );
|
||||
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,37 +18,35 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTooltip : GumpEntry
|
||||
{
|
||||
private int m_Number;
|
||||
public class GumpTooltip : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("tooltip");
|
||||
private int m_Number;
|
||||
|
||||
public GumpTooltip( int number )
|
||||
{
|
||||
m_Number = number;
|
||||
}
|
||||
public GumpTooltip(int number)
|
||||
{
|
||||
m_Number = number;
|
||||
}
|
||||
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta( ref m_Number, value );
|
||||
}
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta(ref m_Number, value);
|
||||
}
|
||||
|
||||
public override string Compile( NetState ns )
|
||||
{
|
||||
return $"{{ tooltip {m_Number} }}";
|
||||
}
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ tooltip {m_Number} }}";
|
||||
}
|
||||
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer( "tooltip" );
|
||||
|
||||
public override void AppendTo( NetState ns, IGumpWriter disp )
|
||||
{
|
||||
disp.AppendLayout( m_LayoutName );
|
||||
disp.AppendLayout( m_Number );
|
||||
}
|
||||
}
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Number);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,58 +20,50 @@
|
|||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class TextRelay
|
||||
{
|
||||
public TextRelay( int entryID, string text )
|
||||
{
|
||||
EntryID = entryID;
|
||||
Text = text;
|
||||
}
|
||||
public class TextRelay
|
||||
{
|
||||
public TextRelay(int entryID, string text)
|
||||
{
|
||||
EntryID = entryID;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public int EntryID { get; }
|
||||
public int EntryID{ get; }
|
||||
|
||||
public string Text { get; }
|
||||
}
|
||||
public string Text{ get; }
|
||||
}
|
||||
|
||||
public class RelayInfo
|
||||
{
|
||||
public RelayInfo( int buttonID, int[] switches, TextRelay[] textEntries )
|
||||
{
|
||||
ButtonID = buttonID;
|
||||
Switches = switches;
|
||||
TextEntries = textEntries;
|
||||
}
|
||||
public class RelayInfo
|
||||
{
|
||||
public RelayInfo(int buttonID, int[] switches, TextRelay[] textEntries)
|
||||
{
|
||||
ButtonID = buttonID;
|
||||
Switches = switches;
|
||||
TextEntries = textEntries;
|
||||
}
|
||||
|
||||
public int ButtonID { get; }
|
||||
public int ButtonID{ get; }
|
||||
|
||||
public int[] Switches { get; }
|
||||
public int[] Switches{ get; }
|
||||
|
||||
public TextRelay[] TextEntries { get; }
|
||||
public TextRelay[] TextEntries{ get; }
|
||||
|
||||
public bool IsSwitched( int switchID )
|
||||
{
|
||||
for ( int i = 0; i < Switches.Length; ++i )
|
||||
{
|
||||
if ( Switches[i] == switchID )
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
public bool IsSwitched(int switchID)
|
||||
{
|
||||
for (int i = 0; i < Switches.Length; ++i)
|
||||
if (Switches[i] == switchID)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public TextRelay GetTextEntry( int entryID )
|
||||
{
|
||||
for ( int i = 0; i < TextEntries.Length; ++i )
|
||||
{
|
||||
if ( TextEntries[i].EntryID == entryID )
|
||||
{
|
||||
return TextEntries[i];
|
||||
}
|
||||
}
|
||||
public TextRelay GetTextEntry(int entryID)
|
||||
{
|
||||
for (int i = 0; i < TextEntries.Length; ++i)
|
||||
if (TextEntries[i].EntryID == entryID)
|
||||
return TextEntries[i];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,32 +22,32 @@ using Server.Network;
|
|||
|
||||
namespace Server.HuePickers
|
||||
{
|
||||
public class HuePicker
|
||||
{
|
||||
private static int m_NextSerial = 1;
|
||||
public class HuePicker
|
||||
{
|
||||
private static int m_NextSerial = 1;
|
||||
|
||||
public int Serial { get; }
|
||||
public HuePicker(int itemID)
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial = m_NextSerial++;
|
||||
} while (Serial == 0);
|
||||
|
||||
public int ItemID { get; }
|
||||
ItemID = itemID;
|
||||
}
|
||||
|
||||
public HuePicker( int itemID )
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial = m_NextSerial++;
|
||||
} while ( Serial == 0 );
|
||||
public int Serial{ get; }
|
||||
|
||||
ItemID = itemID;
|
||||
}
|
||||
public int ItemID{ get; }
|
||||
|
||||
public virtual void OnResponse( int hue )
|
||||
{
|
||||
}
|
||||
public virtual void OnResponse(int hue)
|
||||
{
|
||||
}
|
||||
|
||||
public void SendTo( NetState state )
|
||||
{
|
||||
state.Send( new DisplayHuePicker( this ) );
|
||||
state.AddHuePicker( this );
|
||||
}
|
||||
}
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.Send(new DisplayHuePicker(this));
|
||||
state.AddHuePicker(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,105 +22,105 @@ using System;
|
|||
|
||||
namespace Server.Accounting
|
||||
{
|
||||
public static class AccountGold
|
||||
{
|
||||
public static bool Enabled = false;
|
||||
public static class AccountGold
|
||||
{
|
||||
public static bool Enabled = false;
|
||||
|
||||
/// <summary>
|
||||
/// This amount specifies the value at which point Gold turns to Platinum.
|
||||
/// By default, when 1,000,000,000 Gold is accumulated, it will transform
|
||||
/// into 1 Platinum.
|
||||
/// !!! WARNING !!!
|
||||
/// The client is designed to perceive the currency threashold at 1,000,000,000
|
||||
/// if you change this, it may cause unexpected results when using secure trading.
|
||||
/// </summary>
|
||||
public static int CurrencyThreshold = 1000000000;
|
||||
/// <summary>
|
||||
/// This amount specifies the value at which point Gold turns to Platinum.
|
||||
/// By default, when 1,000,000,000 Gold is accumulated, it will transform
|
||||
/// into 1 Platinum.
|
||||
/// !!! WARNING !!!
|
||||
/// The client is designed to perceive the currency threashold at 1,000,000,000
|
||||
/// if you change this, it may cause unexpected results when using secure trading.
|
||||
/// </summary>
|
||||
public static int CurrencyThreshold = 1000000000;
|
||||
|
||||
/// <summary>
|
||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||
/// when they are added to a bank box container.
|
||||
/// </summary>
|
||||
public static bool ConvertOnBank = true;
|
||||
/// <summary>
|
||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||
/// when they are added to a bank box container.
|
||||
/// </summary>
|
||||
public static bool ConvertOnBank = true;
|
||||
|
||||
/// <summary>
|
||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||
/// when they are added to a secure trade container.
|
||||
/// </summary>
|
||||
public static bool ConvertOnTrade = false;
|
||||
}
|
||||
/// <summary>
|
||||
/// Enables or Disables automatic conversion of Gold and Checks to Bank Currency
|
||||
/// when they are added to a secure trade container.
|
||||
/// </summary>
|
||||
public static bool ConvertOnTrade = false;
|
||||
}
|
||||
|
||||
public interface IGoldAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Gold owned by the player.
|
||||
/// The value does not include the value of Platinum and ranges from
|
||||
/// 0 to 999,999,999 by default.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalGold { get; }
|
||||
public interface IGoldAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Gold owned by the player.
|
||||
/// The value does not include the value of Platinum and ranges from
|
||||
/// 0 to 999,999,999 by default.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalGold{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Platinum owned by the player.
|
||||
/// The value does not include the value of Gold and ranges from
|
||||
/// 0 to 2,147,483,647 by default.
|
||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalPlat { get; }
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Platinum owned by the player.
|
||||
/// The value does not include the value of Gold and ranges from
|
||||
/// 0 to 2,147,483,647 by default.
|
||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalPlat{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Gold into this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be deposited to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositGold(int amount);
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Gold into this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be deposited to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositGold(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Platinum into this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositPlat(int amount);
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Platinum into this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositPlat(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Gold from this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be withdrawn to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawGold(int amount);
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Gold from this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be withdrawn to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawGold(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Platinum from this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawPlat(int amount);
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Platinum from this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawPlat(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Returns total gold inclusive of platinum, capped to Int32.
|
||||
/// This is strictly for backwards compatibility
|
||||
/// </summary>
|
||||
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
||||
long GetTotalGold();
|
||||
}
|
||||
/// <summary>
|
||||
/// Returns total gold inclusive of platinum, capped to Int32.
|
||||
/// This is strictly for backwards compatibility
|
||||
/// </summary>
|
||||
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
||||
long GetTotalGold();
|
||||
}
|
||||
|
||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
||||
{
|
||||
string Username { get; set; }
|
||||
string Email { get; set; }
|
||||
AccessLevel AccessLevel { get; set; }
|
||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
||||
{
|
||||
string Username{ get; set; }
|
||||
string Email{ get; set; }
|
||||
AccessLevel AccessLevel{ get; set; }
|
||||
|
||||
int Length { get; }
|
||||
int Limit { get; }
|
||||
int Count { get; }
|
||||
Mobile this[int index] { get; set; }
|
||||
int Length{ get; }
|
||||
int Limit{ get; }
|
||||
int Count{ get; }
|
||||
Mobile this[int index]{ get; set; }
|
||||
|
||||
void Delete();
|
||||
void SetPassword( string password );
|
||||
bool CheckPassword( string password );
|
||||
}
|
||||
}
|
||||
void Delete();
|
||||
void SetPassword(string password);
|
||||
bool CheckPassword(string password);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,75 +22,75 @@ using System;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public interface IEntity : IPoint3D, IComparable, IComparable<IEntity>
|
||||
{
|
||||
Serial Serial{ get; }
|
||||
Point3D Location{ get; }
|
||||
Map Map{ get; }
|
||||
void MoveToWorld(Point3D location, Map map);
|
||||
bool Deleted { get; }
|
||||
public interface IEntity : IPoint3D, IComparable, IComparable<IEntity>
|
||||
{
|
||||
Serial Serial{ get; }
|
||||
Point3D Location{ get; }
|
||||
Map Map{ get; }
|
||||
bool Deleted{ get; }
|
||||
void MoveToWorld(Point3D location, Map map);
|
||||
|
||||
void Delete();
|
||||
void ProcessDelta();
|
||||
}
|
||||
void Delete();
|
||||
void ProcessDelta();
|
||||
}
|
||||
|
||||
public class Entity : IEntity, IComparable<Entity>
|
||||
{
|
||||
public int CompareTo( IEntity other )
|
||||
{
|
||||
if ( other == null )
|
||||
return -1;
|
||||
public class Entity : IEntity, IComparable<Entity>
|
||||
{
|
||||
public Entity(Serial serial, Point3D loc, Map map)
|
||||
{
|
||||
Serial = serial;
|
||||
Location = loc;
|
||||
Map = map;
|
||||
Deleted = false;
|
||||
}
|
||||
|
||||
return Serial.CompareTo( other.Serial );
|
||||
}
|
||||
public int CompareTo(Entity other)
|
||||
{
|
||||
return CompareTo((IEntity)other);
|
||||
}
|
||||
|
||||
public int CompareTo( Entity other )
|
||||
{
|
||||
return CompareTo( (IEntity) other );
|
||||
}
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
if (other == null)
|
||||
return -1;
|
||||
|
||||
public int CompareTo( object other )
|
||||
{
|
||||
if ( other == null || other is IEntity )
|
||||
return CompareTo( (IEntity) other );
|
||||
return Serial.CompareTo(other.Serial);
|
||||
}
|
||||
|
||||
throw new ArgumentException();
|
||||
}
|
||||
public int CompareTo(object other)
|
||||
{
|
||||
if (other == null || other is IEntity)
|
||||
return CompareTo((IEntity)other);
|
||||
|
||||
public Entity( Serial serial, Point3D loc, Map map )
|
||||
{
|
||||
Serial = serial;
|
||||
Location = loc;
|
||||
Map = map;
|
||||
Deleted = false;
|
||||
}
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
public Serial Serial { get; }
|
||||
public Serial Serial{ get; }
|
||||
|
||||
public Point3D Location { get; private set; }
|
||||
public Point3D Location{ get; private set; }
|
||||
|
||||
public int X => Location.X;
|
||||
public int X => Location.X;
|
||||
|
||||
public int Y => Location.Y;
|
||||
public int Y => Location.Y;
|
||||
|
||||
public int Z => Location.Z;
|
||||
public int Z => Location.Z;
|
||||
|
||||
public Map Map { get; private set; }
|
||||
public Map Map{ get; private set; }
|
||||
|
||||
public virtual void MoveToWorld(Point3D newLocation, Map map)
|
||||
{
|
||||
Location = newLocation;
|
||||
Map = map;
|
||||
}
|
||||
public virtual void MoveToWorld(Point3D newLocation, Map map)
|
||||
{
|
||||
Location = newLocation;
|
||||
Map = map;
|
||||
}
|
||||
|
||||
public bool Deleted { get; }
|
||||
public bool Deleted{ get; }
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
public void ProcessDelta()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,50 +22,50 @@ using System.Collections;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public static class Insensitive
|
||||
{
|
||||
public static IComparer Comparer { get; } = CaseInsensitiveComparer.Default;
|
||||
public static class Insensitive
|
||||
{
|
||||
public static IComparer Comparer{ get; } = CaseInsensitiveComparer.Default;
|
||||
|
||||
public static int Compare( string a, string b )
|
||||
{
|
||||
return Comparer.Compare( a, b );
|
||||
}
|
||||
public static int Compare(string a, string b)
|
||||
{
|
||||
return Comparer.Compare(a, b);
|
||||
}
|
||||
|
||||
public static bool Equals( string a, string b )
|
||||
{
|
||||
if ( a == null && b == null )
|
||||
return true;
|
||||
if ( a == null || b == null || a.Length != b.Length )
|
||||
return false;
|
||||
public static bool Equals(string a, string b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return true;
|
||||
if (a == null || b == null || a.Length != b.Length)
|
||||
return false;
|
||||
|
||||
return ( Comparer.Compare( a, b ) == 0 );
|
||||
}
|
||||
return Comparer.Compare(a, b) == 0;
|
||||
}
|
||||
|
||||
public static bool StartsWith( string a, string b )
|
||||
{
|
||||
if ( a == null || b == null || a.Length < b.Length )
|
||||
return false;
|
||||
public static bool StartsWith(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
return ( Comparer.Compare( a.Substring( 0, b.Length ), b ) == 0 );
|
||||
}
|
||||
return Comparer.Compare(a.Substring(0, b.Length), b) == 0;
|
||||
}
|
||||
|
||||
public static bool EndsWith( string a, string b )
|
||||
{
|
||||
if ( a == null || b == null || a.Length < b.Length )
|
||||
return false;
|
||||
public static bool EndsWith(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
return ( Comparer.Compare( a.Substring( a.Length - b.Length ), b ) == 0 );
|
||||
}
|
||||
return Comparer.Compare(a.Substring(a.Length - b.Length), b) == 0;
|
||||
}
|
||||
|
||||
public static bool Contains( string a, string b )
|
||||
{
|
||||
if ( a == null || b == null || a.Length < b.Length )
|
||||
return false;
|
||||
public static bool Contains(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
a = a.ToLower();
|
||||
b = b.ToLower();
|
||||
a = a.ToLower();
|
||||
b = b.ToLower();
|
||||
|
||||
return ( a.IndexOf( b ) >= 0 );
|
||||
}
|
||||
}
|
||||
return a.IndexOf(b) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,93 +24,91 @@ using Server.Mobiles;
|
|||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public interface IMount
|
||||
{
|
||||
Mobile Rider{ get; set; }
|
||||
void OnRiderDamaged( int amount, Mobile from, bool willKill );
|
||||
}
|
||||
public interface IMount
|
||||
{
|
||||
Mobile Rider{ get; set; }
|
||||
void OnRiderDamaged(int amount, Mobile from, bool willKill);
|
||||
}
|
||||
|
||||
public interface IMountItem
|
||||
{
|
||||
IMount Mount{ get; }
|
||||
}
|
||||
public interface IMountItem
|
||||
{
|
||||
IMount Mount{ get; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IVendor
|
||||
{
|
||||
bool OnBuyItems( Mobile from, List<BuyItemResponse> list );
|
||||
bool OnSellItems( Mobile from, List<SellItemResponse> list );
|
||||
public interface IVendor
|
||||
{
|
||||
DateTime LastRestock{ get; set; }
|
||||
TimeSpan RestockDelay{ get; }
|
||||
bool OnBuyItems(Mobile from, List<BuyItemResponse> list);
|
||||
bool OnSellItems(Mobile from, List<SellItemResponse> list);
|
||||
void Restock();
|
||||
}
|
||||
|
||||
DateTime LastRestock{ get; set; }
|
||||
TimeSpan RestockDelay{ get; }
|
||||
void Restock();
|
||||
}
|
||||
public interface IPoint2D
|
||||
{
|
||||
int X{ get; }
|
||||
int Y{ get; }
|
||||
}
|
||||
|
||||
public interface IPoint2D
|
||||
{
|
||||
int X{ get; }
|
||||
int Y{ get; }
|
||||
}
|
||||
public interface IPoint3D : IPoint2D
|
||||
{
|
||||
int Z{ get; }
|
||||
}
|
||||
|
||||
public interface IPoint3D : IPoint2D
|
||||
{
|
||||
int Z{ get; }
|
||||
}
|
||||
public interface ICarvable
|
||||
{
|
||||
void Carve(Mobile from, Item item);
|
||||
}
|
||||
|
||||
public interface ICarvable
|
||||
{
|
||||
void Carve( Mobile from, Item item );
|
||||
}
|
||||
public interface IWeapon
|
||||
{
|
||||
int MaxRange{ get; }
|
||||
void OnBeforeSwing(Mobile attacker, Mobile defender);
|
||||
TimeSpan OnSwing(Mobile attacker, Mobile defender);
|
||||
void GetStatusDamage(Mobile from, out int min, out int max);
|
||||
}
|
||||
|
||||
public interface IWeapon
|
||||
{
|
||||
int MaxRange{ get; }
|
||||
void OnBeforeSwing( Mobile attacker, Mobile defender );
|
||||
TimeSpan OnSwing( Mobile attacker, Mobile defender );
|
||||
void GetStatusDamage( Mobile from, out int min, out int max );
|
||||
}
|
||||
public interface IHued
|
||||
{
|
||||
int HuedItemID{ get; }
|
||||
}
|
||||
|
||||
public interface IHued
|
||||
{
|
||||
int HuedItemID{ get; }
|
||||
}
|
||||
public interface ISpell
|
||||
{
|
||||
bool IsCasting{ get; }
|
||||
void OnCasterHurt();
|
||||
void OnCasterKilled();
|
||||
void OnConnectionChanged();
|
||||
bool OnCasterMoving(Direction d);
|
||||
bool OnCasterEquipping(Item item);
|
||||
bool OnCasterUsingObject(object o);
|
||||
bool OnCastInTown(Region r);
|
||||
}
|
||||
|
||||
public interface ISpell
|
||||
{
|
||||
bool IsCasting{ get; }
|
||||
void OnCasterHurt();
|
||||
void OnCasterKilled();
|
||||
void OnConnectionChanged();
|
||||
bool OnCasterMoving( Direction d );
|
||||
bool OnCasterEquiping( Item item );
|
||||
bool OnCasterUsingObject( object o );
|
||||
bool OnCastInTown( Region r );
|
||||
}
|
||||
public interface IParty
|
||||
{
|
||||
void OnStamChanged(Mobile m);
|
||||
void OnManaChanged(Mobile m);
|
||||
void OnStatsQuery(Mobile beholder, Mobile beheld);
|
||||
}
|
||||
|
||||
public interface IParty
|
||||
{
|
||||
void OnStamChanged( Mobile m );
|
||||
void OnManaChanged( Mobile m );
|
||||
void OnStatsQuery( Mobile beholder, Mobile beheld );
|
||||
}
|
||||
public interface ISpawner
|
||||
{
|
||||
bool UnlinkOnTaming{ get; }
|
||||
Point3D HomeLocation{ get; }
|
||||
int HomeRange{ get; }
|
||||
Region Region{ get; }
|
||||
|
||||
public interface ISpawner
|
||||
{
|
||||
bool UnlinkOnTaming { get; }
|
||||
Point3D HomeLocation { get; }
|
||||
int HomeRange { get; }
|
||||
Region Region { get; }
|
||||
void Remove(ISpawnable spawn);
|
||||
}
|
||||
|
||||
void Remove(ISpawnable spawn);
|
||||
}
|
||||
|
||||
public interface ISpawnable : IEntity
|
||||
{
|
||||
void OnBeforeSpawn(Point3D location, Map map);
|
||||
void OnAfterSpawn();
|
||||
|
||||
ISpawner Spawner { get; set; }
|
||||
}
|
||||
}
|
||||
public interface ISpawnable : IEntity
|
||||
{
|
||||
ISpawner Spawner{ get; set; }
|
||||
void OnBeforeSpawn(Point3D location, Map map);
|
||||
void OnAfterSpawn();
|
||||
}
|
||||
}
|
||||
8867
Server/Item.cs
8867
Server/Item.cs
File diff suppressed because it is too large
Load diff
|
|
@ -23,39 +23,36 @@ using System.IO;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public static class ItemBounds
|
||||
{
|
||||
public static Rectangle2D[] Table { get; }
|
||||
public static class ItemBounds
|
||||
{
|
||||
static ItemBounds()
|
||||
{
|
||||
Table = new Rectangle2D[TileData.ItemTable.Length];
|
||||
|
||||
static ItemBounds()
|
||||
{
|
||||
Table = new Rectangle2D[TileData.ItemTable.Length];
|
||||
if (File.Exists("Data/Binary/Bounds.bin"))
|
||||
using (FileStream fs = new FileStream("Data/Binary/Bounds.bin", FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read))
|
||||
{
|
||||
BinaryReader bin = new BinaryReader(fs);
|
||||
|
||||
if ( File.Exists( "Data/Binary/Bounds.bin" ) )
|
||||
{
|
||||
using ( FileStream fs = new FileStream( "Data/Binary/Bounds.bin", FileMode.Open, FileAccess.Read, FileShare.Read ) )
|
||||
{
|
||||
BinaryReader bin = new BinaryReader( fs );
|
||||
int count = Math.Min(Table.Length, (int)(fs.Length / 8));
|
||||
|
||||
int count = Math.Min( Table.Length, (int)( fs.Length / 8 ) );
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int xMin = bin.ReadInt16();
|
||||
int yMin = bin.ReadInt16();
|
||||
int xMax = bin.ReadInt16();
|
||||
int yMax = bin.ReadInt16();
|
||||
|
||||
for ( int i = 0; i < count; ++i )
|
||||
{
|
||||
int xMin = bin.ReadInt16();
|
||||
int yMin = bin.ReadInt16();
|
||||
int xMax = bin.ReadInt16();
|
||||
int yMax = bin.ReadInt16();
|
||||
Table[i].Set(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
|
||||
}
|
||||
|
||||
Table[i].Set( xMin, yMin, (xMax - xMin) + 1, (yMax - yMin) + 1 );
|
||||
}
|
||||
bin.Close();
|
||||
}
|
||||
else
|
||||
Console.WriteLine("Warning: Data/Binary/Bounds.bin does not exist");
|
||||
}
|
||||
|
||||
bin.Close();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine( "Warning: Data/Binary/Bounds.bin does not exist" );
|
||||
}
|
||||
}
|
||||
}
|
||||
public static Rectangle2D[] Table{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -22,140 +22,144 @@ using System;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class BaseMulti : Item
|
||||
{
|
||||
[Constructible]
|
||||
public BaseMulti( int itemID ) : base( itemID )
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
public class BaseMulti : Item
|
||||
{
|
||||
[Constructible]
|
||||
public BaseMulti(int itemID) : base(itemID)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public BaseMulti( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
public BaseMulti(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public override int ItemID {
|
||||
get => base.ItemID;
|
||||
set {
|
||||
if ( base.ItemID != value ) {
|
||||
Map facet = ( Parent == null ? Map : null );
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override int ItemID
|
||||
{
|
||||
get => base.ItemID;
|
||||
set
|
||||
{
|
||||
if (base.ItemID != value)
|
||||
{
|
||||
Map facet = Parent == null ? Map : null;
|
||||
|
||||
facet?.OnLeave( this );
|
||||
facet?.OnLeave(this);
|
||||
|
||||
base.ItemID = value;
|
||||
base.ItemID = value;
|
||||
|
||||
facet?.OnEnter( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
facet?.OnEnter(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Obsolete( "Replace with calls to OnLeave and OnEnter surrounding component invalidation.", true )]
|
||||
public virtual void RefreshComponents()
|
||||
{
|
||||
if ( Parent == null ) {
|
||||
Map facet = Map;
|
||||
public override int LabelNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
|
||||
if ( facet != null ) {
|
||||
facet.OnLeave( this );
|
||||
facet.OnEnter( this );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (mcl.List.Length > 0)
|
||||
{
|
||||
int id = mcl.List[0].m_ItemID;
|
||||
|
||||
public override int LabelNumber
|
||||
{
|
||||
get
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
if (id < 0x4000)
|
||||
return 1020000 + id;
|
||||
return 1078872 + id;
|
||||
}
|
||||
|
||||
if ( mcl.List.Length > 0 ) {
|
||||
int id = mcl.List[0].m_ItemID;
|
||||
return base.LabelNumber;
|
||||
}
|
||||
}
|
||||
|
||||
if ( id < 0x4000 )
|
||||
return 1020000 + id;
|
||||
return 1078872 + id;
|
||||
}
|
||||
public virtual bool AllowsRelativeDrop => false;
|
||||
|
||||
return base.LabelNumber;
|
||||
}
|
||||
}
|
||||
public virtual MultiComponentList Components => MultiData.GetComponents(ItemID);
|
||||
|
||||
public virtual bool AllowsRelativeDrop => false;
|
||||
[Obsolete("Replace with calls to OnLeave and OnEnter surrounding component invalidation.", true)]
|
||||
public virtual void RefreshComponents()
|
||||
{
|
||||
if (Parent == null)
|
||||
{
|
||||
Map facet = Map;
|
||||
|
||||
public override int GetMaxUpdateRange()
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
if (facet != null)
|
||||
{
|
||||
facet.OnLeave(this);
|
||||
facet.OnEnter(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override int GetUpdateRange( Mobile m )
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
public override int GetMaxUpdateRange()
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
|
||||
public virtual MultiComponentList Components => MultiData.GetComponents( ItemID );
|
||||
public override int GetUpdateRange(Mobile m)
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
|
||||
public virtual bool Contains( Point2D p )
|
||||
{
|
||||
return Contains( p.m_X, p.m_Y );
|
||||
}
|
||||
public virtual bool Contains(Point2D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public virtual bool Contains( Point3D p )
|
||||
{
|
||||
return Contains( p.m_X, p.m_Y );
|
||||
}
|
||||
public virtual bool Contains(Point3D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public virtual bool Contains( IPoint3D p )
|
||||
{
|
||||
return Contains( p.X, p.Y );
|
||||
}
|
||||
public virtual bool Contains(IPoint3D p)
|
||||
{
|
||||
return Contains(p.X, p.Y);
|
||||
}
|
||||
|
||||
public virtual bool Contains( int x, int y )
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
public virtual bool Contains(int x, int y)
|
||||
{
|
||||
MultiComponentList mcl = Components;
|
||||
|
||||
x -= X + mcl.Min.m_X;
|
||||
y -= Y + mcl.Min.m_Y;
|
||||
x -= X + mcl.Min.m_X;
|
||||
y -= Y + mcl.Min.m_Y;
|
||||
|
||||
return x >= 0
|
||||
&& x < mcl.Width
|
||||
&& y >= 0
|
||||
&& y < mcl.Height
|
||||
&& mcl.Tiles[x][y].Length > 0;
|
||||
}
|
||||
return x >= 0
|
||||
&& x < mcl.Width
|
||||
&& y >= 0
|
||||
&& y < mcl.Height
|
||||
&& mcl.Tiles[x][y].Length > 0;
|
||||
}
|
||||
|
||||
public bool Contains( Mobile m )
|
||||
{
|
||||
if ( m.Map == Map )
|
||||
return Contains( m.X, m.Y );
|
||||
return false;
|
||||
}
|
||||
public bool Contains(Mobile m)
|
||||
{
|
||||
if (m.Map == Map)
|
||||
return Contains(m.X, m.Y);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Contains( Item item )
|
||||
{
|
||||
if ( item.Map == Map )
|
||||
return Contains( item.X, item.Y );
|
||||
return false;
|
||||
}
|
||||
public bool Contains(Item item)
|
||||
{
|
||||
if (item.Map == Map)
|
||||
return Contains(item.X, item.Y);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write( (int) 1 ); // version
|
||||
}
|
||||
writer.Write(1); // version
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
int version = reader.ReadInt();
|
||||
|
||||
if ( version == 0 ) {
|
||||
if ( ItemID >= 0x4000 ) {
|
||||
ItemID -= 0x4000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (version == 0)
|
||||
if (ItemID >= 0x4000)
|
||||
ItemID -= 0x4000;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,133 +18,128 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
|
||||
using Server.Accounting;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class BankBox : Container
|
||||
{
|
||||
public override int DefaultMaxWeight => 0;
|
||||
public class BankBox : Container
|
||||
{
|
||||
public BankBox(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsVirtualItem => true;
|
||||
public BankBox(Mobile owner) : base(0xE7C)
|
||||
{
|
||||
Layer = Layer.Bank;
|
||||
Movable = false;
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public BankBox( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
public override int DefaultMaxWeight => 0;
|
||||
|
||||
public Mobile Owner { get; private set; }
|
||||
public override bool IsVirtualItem => true;
|
||||
|
||||
public bool Opened { get; private set; }
|
||||
public Mobile Owner{ get; private set; }
|
||||
|
||||
public void Open()
|
||||
{
|
||||
Opened = true;
|
||||
public bool Opened{ get; private set; }
|
||||
|
||||
if ( Owner != null )
|
||||
{
|
||||
Owner.PrivateOverheadMessage( MessageType.Regular, 0x3B2, true,
|
||||
$"Bank container has {TotalItems} items, {TotalWeight} stones", Owner.NetState );
|
||||
Owner.Send( new EquipUpdate( this ) );
|
||||
DisplayTo( Owner );
|
||||
}
|
||||
}
|
||||
public static bool SendDeleteOnClose{ get; set; }
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
public void Open()
|
||||
{
|
||||
Opened = true;
|
||||
|
||||
writer.Write( (int) 0 ); // version
|
||||
if (Owner != null)
|
||||
{
|
||||
Owner.PrivateOverheadMessage(MessageType.Regular, 0x3B2, true,
|
||||
$"Bank container has {TotalItems} items, {TotalWeight} stones", Owner.NetState);
|
||||
Owner.Send(new EquipUpdate(this));
|
||||
DisplayTo(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
writer.Write( (Mobile) Owner );
|
||||
writer.Write( (bool) Opened );
|
||||
}
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
writer.Write(0); // version
|
||||
|
||||
int version = reader.ReadInt();
|
||||
writer.Write(Owner);
|
||||
writer.Write(Opened);
|
||||
}
|
||||
|
||||
switch ( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Owner = reader.ReadMobile();
|
||||
Opened = reader.ReadBool();
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
if ( Owner == null )
|
||||
Delete();
|
||||
int version = reader.ReadInt();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Owner = reader.ReadMobile();
|
||||
Opened = reader.ReadBool();
|
||||
|
||||
if ( ItemID == 0xE41 )
|
||||
ItemID = 0xE7C;
|
||||
}
|
||||
if (Owner == null)
|
||||
Delete();
|
||||
|
||||
public static bool SendDeleteOnClose { get; set; }
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Opened = false;
|
||||
if (ItemID == 0xE41)
|
||||
ItemID = 0xE7C;
|
||||
}
|
||||
|
||||
if ( Owner != null && SendDeleteOnClose )
|
||||
Owner.Send( RemovePacket );
|
||||
}
|
||||
public void Close()
|
||||
{
|
||||
Opened = false;
|
||||
|
||||
public override void OnSingleClick( Mobile from )
|
||||
{
|
||||
}
|
||||
if (Owner != null && SendDeleteOnClose)
|
||||
Owner.Send(RemovePacket);
|
||||
}
|
||||
|
||||
public override void OnDoubleClick( Mobile from )
|
||||
{
|
||||
}
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public override DeathMoveResult OnParentDeath( Mobile parent )
|
||||
{
|
||||
return DeathMoveResult.RemainEquipped;
|
||||
}
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public BankBox( Mobile owner ) : base( 0xE7C )
|
||||
{
|
||||
Layer = Layer.Bank;
|
||||
Movable = false;
|
||||
Owner = owner;
|
||||
}
|
||||
public override DeathMoveResult OnParentDeath(Mobile parent)
|
||||
{
|
||||
return DeathMoveResult.RemainEquipped;
|
||||
}
|
||||
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
if ( ( check == Owner && Opened ) || check.AccessLevel >= AccessLevel.GameMaster )
|
||||
return base.IsAccessibleTo (check);
|
||||
return false;
|
||||
}
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
if (check == Owner && Opened || check.AccessLevel >= AccessLevel.GameMaster)
|
||||
return base.IsAccessibleTo(check);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnDragDrop( Mobile from, Item dropped )
|
||||
{
|
||||
if ( ( from == Owner && Opened ) || from.AccessLevel >= AccessLevel.GameMaster )
|
||||
return base.OnDragDrop( from, dropped );
|
||||
return false;
|
||||
}
|
||||
public override bool OnDragDrop(Mobile from, Item dropped)
|
||||
{
|
||||
if (from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster)
|
||||
return base.OnDragDrop(from, dropped);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
|
||||
{
|
||||
if ( ( from == Owner && Opened ) || from.AccessLevel >= AccessLevel.GameMaster )
|
||||
return base.OnDragDropInto (from, item, p);
|
||||
return false;
|
||||
}
|
||||
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
|
||||
{
|
||||
if (from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster)
|
||||
return base.OnDragDropInto(from, item, p);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override int GetTotal(TotalType type)
|
||||
{
|
||||
if (AccountGold.Enabled && Owner?.Account != null && type == TotalType.Gold)
|
||||
{
|
||||
return Owner.Account.TotalGold;
|
||||
}
|
||||
public override int GetTotal(TotalType type)
|
||||
{
|
||||
if (AccountGold.Enabled && Owner?.Account != null && type == TotalType.Gold) return Owner.Account.TotalGold;
|
||||
|
||||
return base.GetTotal(type);
|
||||
}
|
||||
}
|
||||
return base.GetTotal(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -23,124 +23,100 @@ using Server.Network;
|
|||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SecureTradeContainer : Container
|
||||
{
|
||||
public SecureTrade Trade { get; }
|
||||
public class SecureTradeContainer : Container
|
||||
{
|
||||
public SecureTradeContainer(SecureTrade trade) : base(0x1E5E)
|
||||
{
|
||||
Trade = trade;
|
||||
|
||||
public SecureTradeContainer( SecureTrade trade ) : base( 0x1E5E )
|
||||
{
|
||||
Trade = trade;
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
Movable = false;
|
||||
}
|
||||
public SecureTradeContainer(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public SecureTradeContainer( Serial serial ) : base( serial )
|
||||
{
|
||||
}
|
||||
public SecureTrade Trade{ get; }
|
||||
|
||||
public override bool CheckHold( Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight )
|
||||
{
|
||||
if (item == Trade.From.VirtualCheck || item == Trade.To.VirtualCheck)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
|
||||
{
|
||||
if (item == Trade.From.VirtualCheck || item == Trade.To.VirtualCheck) return true;
|
||||
|
||||
Mobile to;
|
||||
Mobile to;
|
||||
|
||||
if ( Trade.From.Container != this )
|
||||
to = Trade.From.Mobile;
|
||||
else
|
||||
to = Trade.To.Mobile;
|
||||
if (Trade.From.Container != this)
|
||||
to = Trade.From.Mobile;
|
||||
else
|
||||
to = Trade.To.Mobile;
|
||||
|
||||
return m.CheckTrade( to, item, this, message, checkItems, plusItems, plusWeight );
|
||||
}
|
||||
return m.CheckTrade(to, item, this, message, checkItems, plusItems, plusWeight);
|
||||
}
|
||||
|
||||
public override bool CheckLift( Mobile from, Item item, ref LRReason reject )
|
||||
{
|
||||
reject = LRReason.CannotLift;
|
||||
return false;
|
||||
}
|
||||
public override bool CheckLift(Mobile from, Item item, ref LRReason reject)
|
||||
{
|
||||
reject = LRReason.CannotLift;
|
||||
return false;
|
||||
}
|
||||
|
||||
public override bool IsAccessibleTo( Mobile check )
|
||||
{
|
||||
if ( !IsChildOf( check ) || Trade == null || !Trade.Valid )
|
||||
return false;
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
if (!IsChildOf(check) || Trade == null || !Trade.Valid)
|
||||
return false;
|
||||
|
||||
return base.IsAccessibleTo( check );
|
||||
}
|
||||
return base.IsAccessibleTo(check);
|
||||
}
|
||||
|
||||
public override void OnItemAdded( Item item )
|
||||
{
|
||||
if ( !(item is VirtualCheck) )
|
||||
{
|
||||
ClearChecks();
|
||||
}
|
||||
}
|
||||
public override void OnItemAdded(Item item)
|
||||
{
|
||||
if (!(item is VirtualCheck)) ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnItemRemoved( Item item )
|
||||
{
|
||||
if ( !(item is VirtualCheck) )
|
||||
{
|
||||
ClearChecks();
|
||||
}
|
||||
}
|
||||
public override void OnItemRemoved(Item item)
|
||||
{
|
||||
if (!(item is VirtualCheck)) ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnSubItemAdded( Item item )
|
||||
{
|
||||
if ( !(item is VirtualCheck) )
|
||||
{
|
||||
ClearChecks();
|
||||
}
|
||||
}
|
||||
public override void OnSubItemAdded(Item item)
|
||||
{
|
||||
if (!(item is VirtualCheck)) ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnSubItemRemoved( Item item )
|
||||
{
|
||||
if ( !(item is VirtualCheck) )
|
||||
{
|
||||
ClearChecks();
|
||||
}
|
||||
}
|
||||
public override void OnSubItemRemoved(Item item)
|
||||
{
|
||||
if (!(item is VirtualCheck)) ClearChecks();
|
||||
}
|
||||
|
||||
public void ClearChecks( )
|
||||
{
|
||||
if ( Trade != null )
|
||||
{
|
||||
if ( Trade.From != null && !Trade.From.IsDisposed )
|
||||
{
|
||||
Trade.From.Accepted = false;
|
||||
}
|
||||
public void ClearChecks()
|
||||
{
|
||||
if (Trade != null)
|
||||
{
|
||||
if (Trade.From != null && !Trade.From.IsDisposed) Trade.From.Accepted = false;
|
||||
|
||||
if ( Trade.To != null && !Trade.To.IsDisposed )
|
||||
{
|
||||
Trade.To.Accepted = false;
|
||||
}
|
||||
if (Trade.To != null && !Trade.To.IsDisposed) Trade.To.Accepted = false;
|
||||
|
||||
Trade.Update();
|
||||
}
|
||||
}
|
||||
Trade.Update();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsChildVisibleTo( Mobile m, Item child )
|
||||
{
|
||||
if (child is VirtualCheck)
|
||||
{
|
||||
return AccountGold.Enabled && (m.NetState == null || !m.NetState.NewSecureTrading);
|
||||
}
|
||||
public override bool IsChildVisibleTo(Mobile m, Item child)
|
||||
{
|
||||
if (child is VirtualCheck) return AccountGold.Enabled && (m.NetState == null || !m.NetState.NewSecureTrading);
|
||||
|
||||
return base.IsChildVisibleTo(m, child);
|
||||
}
|
||||
return base.IsChildVisibleTo(m, child);
|
||||
}
|
||||
|
||||
public override void Serialize( GenericWriter writer )
|
||||
{
|
||||
base.Serialize( writer );
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write( (int) 0 ); // version
|
||||
}
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize( GenericReader reader )
|
||||
{
|
||||
base.Deserialize( reader );
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,391 +1,367 @@
|
|||
#region Header
|
||||
|
||||
// **********
|
||||
// ServUO - VirtualCheck.cs
|
||||
// **********
|
||||
|
||||
#endregion
|
||||
|
||||
#region References
|
||||
using System;
|
||||
|
||||
using System.Drawing;
|
||||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class VirtualCheck : Item
|
||||
{
|
||||
public static bool UseEditGump = false;
|
||||
|
||||
public override bool IsVirtualItem => true;
|
||||
|
||||
public override bool DisplayWeight => false;
|
||||
public override bool DisplayLootType => false;
|
||||
|
||||
public override double DefaultWeight => 0;
|
||||
|
||||
public override string DefaultName => "Offer Of Currency";
|
||||
|
||||
public EditGump Editor { get; private set; }
|
||||
|
||||
private int _Plat;
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Plat
|
||||
{
|
||||
get => _Plat;
|
||||
set
|
||||
{
|
||||
_Plat = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
private int _Gold;
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Gold
|
||||
{
|
||||
get => _Gold;
|
||||
set
|
||||
{
|
||||
_Gold = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public VirtualCheck()
|
||||
: this(0, 0)
|
||||
{ }
|
||||
|
||||
public VirtualCheck(int plat, int gold)
|
||||
: base(0x14F0)
|
||||
{
|
||||
Plat = plat;
|
||||
Gold = gold;
|
||||
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public VirtualCheck(Serial serial)
|
||||
: base(serial)
|
||||
{ }
|
||||
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
var c = GetSecureTradeCont();
|
||||
|
||||
if (check == null || c == null)
|
||||
{
|
||||
return base.IsAccessibleTo(check);
|
||||
}
|
||||
|
||||
return c.RootParent == check && IsChildOf(c);
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade(Mobile from)
|
||||
{
|
||||
if (UseEditGump && IsAccessibleTo(from))
|
||||
{
|
||||
if (Editor?.Check == null || Editor.Check.Deleted)
|
||||
{
|
||||
Editor = new EditGump(from, this);
|
||||
Editor.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.Refresh(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
|
||||
base.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
LabelTo(from, "Offer: {0:#,0} platinum, {1:#,0} gold", Plat, Gold);
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(1060738, $"{Plat:#,0} platinum, {Gold:#,0} gold"); // value: ~1_val~
|
||||
}
|
||||
|
||||
public void UpdateTrade(Mobile user)
|
||||
{
|
||||
var c = GetSecureTradeCont();
|
||||
|
||||
if (c?.Trade == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (user == c.Trade.From.Mobile)
|
||||
{
|
||||
c.Trade.UpdateFromCurrency();
|
||||
}
|
||||
else if (user == c.Trade.To.Mobile)
|
||||
{
|
||||
c.Trade.UpdateToCurrency();
|
||||
}
|
||||
|
||||
c.ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{ }
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
public class EditGump : Gump
|
||||
{
|
||||
public enum Buttons
|
||||
{
|
||||
Close,
|
||||
Clear,
|
||||
Accept,
|
||||
AllPlat,
|
||||
AllGold
|
||||
}
|
||||
|
||||
private int _Plat, _Gold;
|
||||
|
||||
public Mobile User { get; private set; }
|
||||
public VirtualCheck Check { get; private set; }
|
||||
|
||||
public EditGump(Mobile user, VirtualCheck check)
|
||||
: base(50, 50)
|
||||
{
|
||||
User = user;
|
||||
Check = check;
|
||||
|
||||
_Plat = Check.Plat;
|
||||
_Gold = Check.Gold;
|
||||
|
||||
Closable = true;
|
||||
Disposable = true;
|
||||
Dragable = true;
|
||||
Resizable = false;
|
||||
|
||||
User.CloseGump(GetType());
|
||||
|
||||
CompileLayout();
|
||||
}
|
||||
|
||||
public override void OnServerClose(NetState owner)
|
||||
{
|
||||
base.OnServerClose(owner);
|
||||
|
||||
if (Check != null && !Check.Deleted)
|
||||
{
|
||||
Check.UpdateTrade(User);
|
||||
}
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
User.CloseGump(GetType());
|
||||
|
||||
if (Check != null && !Check.Deleted)
|
||||
{
|
||||
Check.UpdateTrade(User);
|
||||
}
|
||||
else
|
||||
{
|
||||
Check = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void Send()
|
||||
{
|
||||
if (Check != null && !Check.Deleted)
|
||||
{
|
||||
User.SendGump(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Refresh(bool recompile)
|
||||
{
|
||||
if (Check == null || Check.Deleted)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (recompile)
|
||||
{
|
||||
CompileLayout();
|
||||
}
|
||||
|
||||
Close();
|
||||
Send();
|
||||
}
|
||||
|
||||
private void CompileLayout()
|
||||
{
|
||||
if (Check == null || Check.Deleted)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
Entries.ForEach(e => e.Parent = null);
|
||||
Entries.Clear();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 400, 160, 3500);
|
||||
|
||||
// Title
|
||||
AddImageTiled(25, 35, 350, 3, 96);
|
||||
AddImage(10, 8, 113);
|
||||
AddImage(360, 8, 113);
|
||||
|
||||
var title =
|
||||
$"<BASEFONT COLOR=#{Color.DarkSlateGray.ToArgb():X}><CENTER>BANK OF {User.RawName.ToUpper()}</CENTER>";
|
||||
|
||||
AddHtml(40, 15, 320, 20, title, false, false);
|
||||
|
||||
// Platinum Row
|
||||
AddBackground(15, 60, 175, 20, 9300);
|
||||
AddBackground(20, 45, 165, 30, 9350);
|
||||
AddItem(20, 45, 3826); // Plat
|
||||
AddLabel(60, 50, 0, User.Account.TotalPlat.ToString("#,0"));
|
||||
|
||||
AddButton(195, 50, 95, 95, (int)Buttons.AllPlat, GumpButtonType.Reply, 0); // ->
|
||||
|
||||
AddBackground(210, 60, 175, 20, 9300);
|
||||
AddBackground(215, 45, 165, 30, 9350);
|
||||
AddTextEntry(225, 50, 145, 20, 0, 0, _Plat.ToString(), User.Account.TotalPlat.ToString().Length);
|
||||
|
||||
// Gold Row
|
||||
AddBackground(15, 100, 175, 20, 9300);
|
||||
AddBackground(20, 85, 165, 30, 9350);
|
||||
AddItem(20, 85, 3823); // Gold
|
||||
AddLabel(60, 90, 0, User.Account.TotalGold.ToString("#,0"));
|
||||
|
||||
AddButton(195, 90, 95, 95, (int)Buttons.AllGold, GumpButtonType.Reply, 0); // ->
|
||||
|
||||
AddBackground(210, 100, 175, 20, 9300);
|
||||
AddBackground(215, 85, 165, 30, 9350);
|
||||
AddTextEntry(225, 90, 145, 20, 0, 1, _Gold.ToString(), User.Account.TotalGold.ToString().Length);
|
||||
|
||||
// Buttons
|
||||
AddButton(20, 128, 12006, 12007, (int)Buttons.Close, GumpButtonType.Reply, 0);
|
||||
AddButton(215, 128, 12003, 12004, (int)Buttons.Clear, GumpButtonType.Reply, 0);
|
||||
AddButton(305, 128, 12000, 12002, (int)Buttons.Accept, GumpButtonType.Reply, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (Check == null || Check.Deleted || sender.Mobile != User)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
bool refresh = false, updated = false;
|
||||
|
||||
switch ((Buttons)info.ButtonID)
|
||||
{
|
||||
case Buttons.Close:
|
||||
break;
|
||||
case Buttons.Clear:
|
||||
{
|
||||
_Plat = _Gold = 0;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.Accept:
|
||||
{
|
||||
var platText = info.GetTextEntry(0).Text;
|
||||
var goldText = info.GetTextEntry(1).Text;
|
||||
|
||||
if (!int.TryParse(platText, out _Plat))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of platinum.");
|
||||
refresh = true;
|
||||
}
|
||||
else if (!int.TryParse(goldText, out _Gold))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of gold.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalPlat = User.Account.TotalPlat;
|
||||
int totalGold = User.Account.TotalGold;
|
||||
|
||||
if (totalPlat < _Plat || totalGold < _Gold)
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
_Gold = User.Account.TotalGold;
|
||||
User.SendMessage("You do not have that much currency.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check.Plat = _Plat;
|
||||
Check.Gold = _Gold;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Buttons.AllPlat:
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.AllGold:
|
||||
{
|
||||
_Gold = User.Account.TotalGold;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
{
|
||||
User.SendMessage("Your offer has been updated.");
|
||||
}
|
||||
|
||||
if (refresh && Check != null && !Check.Deleted)
|
||||
{
|
||||
Refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public sealed class VirtualCheck : Item
|
||||
{
|
||||
public static bool UseEditGump = false;
|
||||
|
||||
private int _Gold;
|
||||
|
||||
private int _Plat;
|
||||
|
||||
public VirtualCheck()
|
||||
: this(0, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public VirtualCheck(int plat, int gold)
|
||||
: base(0x14F0)
|
||||
{
|
||||
Plat = plat;
|
||||
Gold = gold;
|
||||
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public VirtualCheck(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsVirtualItem => true;
|
||||
|
||||
public override bool DisplayWeight => false;
|
||||
public override bool DisplayLootType => false;
|
||||
|
||||
public override double DefaultWeight => 0;
|
||||
|
||||
public override string DefaultName => "Offer Of Currency";
|
||||
|
||||
public EditGump Editor{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Plat
|
||||
{
|
||||
get => _Plat;
|
||||
set
|
||||
{
|
||||
_Plat = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Gold
|
||||
{
|
||||
get => _Gold;
|
||||
set
|
||||
{
|
||||
_Gold = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
SecureTradeContainer c = GetSecureTradeCont();
|
||||
|
||||
if (check == null || c == null) return base.IsAccessibleTo(check);
|
||||
|
||||
return c.RootParent == check && IsChildOf(c);
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade(Mobile from)
|
||||
{
|
||||
if (UseEditGump && IsAccessibleTo(from))
|
||||
{
|
||||
if (Editor?.Check == null || Editor.Check.Deleted)
|
||||
{
|
||||
Editor = new EditGump(from, this);
|
||||
Editor.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.Refresh(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
|
||||
base.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
LabelTo(from, "Offer: {0:#,0} platinum, {1:#,0} gold", Plat, Gold);
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(1060738, $"{Plat:#,0} platinum, {Gold:#,0} gold"); // value: ~1_val~
|
||||
}
|
||||
|
||||
public void UpdateTrade(Mobile user)
|
||||
{
|
||||
SecureTradeContainer c = GetSecureTradeCont();
|
||||
|
||||
if (c?.Trade == null) return;
|
||||
|
||||
if (user == c.Trade.From.Mobile)
|
||||
c.Trade.UpdateFromCurrency();
|
||||
else if (user == c.Trade.To.Mobile) c.Trade.UpdateToCurrency();
|
||||
|
||||
c.ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
public class EditGump : Gump
|
||||
{
|
||||
public enum Buttons
|
||||
{
|
||||
Close,
|
||||
Clear,
|
||||
Accept,
|
||||
AllPlat,
|
||||
AllGold
|
||||
}
|
||||
|
||||
private int _Plat, _Gold;
|
||||
|
||||
public EditGump(Mobile user, VirtualCheck check)
|
||||
: base(50, 50)
|
||||
{
|
||||
User = user;
|
||||
Check = check;
|
||||
|
||||
_Plat = Check.Plat;
|
||||
_Gold = Check.Gold;
|
||||
|
||||
Closable = true;
|
||||
Disposable = true;
|
||||
Dragable = true;
|
||||
Resizable = false;
|
||||
|
||||
User.CloseGump(GetType());
|
||||
|
||||
CompileLayout();
|
||||
}
|
||||
|
||||
public Mobile User{ get; }
|
||||
public VirtualCheck Check{ get; private set; }
|
||||
|
||||
public override void OnServerClose(NetState owner)
|
||||
{
|
||||
base.OnServerClose(owner);
|
||||
|
||||
if (Check != null && !Check.Deleted) Check.UpdateTrade(User);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
User.CloseGump(GetType());
|
||||
|
||||
if (Check != null && !Check.Deleted)
|
||||
Check.UpdateTrade(User);
|
||||
else
|
||||
Check = null;
|
||||
}
|
||||
|
||||
public void Send()
|
||||
{
|
||||
if (Check != null && !Check.Deleted)
|
||||
User.SendGump(this);
|
||||
else
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Refresh(bool recompile)
|
||||
{
|
||||
if (Check == null || Check.Deleted)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (recompile) CompileLayout();
|
||||
|
||||
Close();
|
||||
Send();
|
||||
}
|
||||
|
||||
private void CompileLayout()
|
||||
{
|
||||
if (Check == null || Check.Deleted) return;
|
||||
|
||||
Entries.ForEach(e => e.Parent = null);
|
||||
Entries.Clear();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 400, 160, 3500);
|
||||
|
||||
// Title
|
||||
AddImageTiled(25, 35, 350, 3, 96);
|
||||
AddImage(10, 8, 113);
|
||||
AddImage(360, 8, 113);
|
||||
|
||||
string title =
|
||||
$"<BASEFONT COLOR=#{Color.DarkSlateGray.ToArgb():X}><CENTER>BANK OF {User.RawName.ToUpper()}</CENTER>";
|
||||
|
||||
AddHtml(40, 15, 320, 20, title, false, false);
|
||||
|
||||
// Platinum Row
|
||||
AddBackground(15, 60, 175, 20, 9300);
|
||||
AddBackground(20, 45, 165, 30, 9350);
|
||||
AddItem(20, 45, 3826); // Plat
|
||||
AddLabel(60, 50, 0, User.Account.TotalPlat.ToString("#,0"));
|
||||
|
||||
AddButton(195, 50, 95, 95, (int)Buttons.AllPlat, GumpButtonType.Reply, 0); // ->
|
||||
|
||||
AddBackground(210, 60, 175, 20, 9300);
|
||||
AddBackground(215, 45, 165, 30, 9350);
|
||||
AddTextEntry(225, 50, 145, 20, 0, 0, _Plat.ToString(), User.Account.TotalPlat.ToString().Length);
|
||||
|
||||
// Gold Row
|
||||
AddBackground(15, 100, 175, 20, 9300);
|
||||
AddBackground(20, 85, 165, 30, 9350);
|
||||
AddItem(20, 85, 3823); // Gold
|
||||
AddLabel(60, 90, 0, User.Account.TotalGold.ToString("#,0"));
|
||||
|
||||
AddButton(195, 90, 95, 95, (int)Buttons.AllGold, GumpButtonType.Reply, 0); // ->
|
||||
|
||||
AddBackground(210, 100, 175, 20, 9300);
|
||||
AddBackground(215, 85, 165, 30, 9350);
|
||||
AddTextEntry(225, 90, 145, 20, 0, 1, _Gold.ToString(), User.Account.TotalGold.ToString().Length);
|
||||
|
||||
// Buttons
|
||||
AddButton(20, 128, 12006, 12007, (int)Buttons.Close, GumpButtonType.Reply, 0);
|
||||
AddButton(215, 128, 12003, 12004, (int)Buttons.Clear, GumpButtonType.Reply, 0);
|
||||
AddButton(305, 128, 12000, 12002, (int)Buttons.Accept, GumpButtonType.Reply, 0);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (Check == null || Check.Deleted || sender.Mobile != User)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
bool refresh = false, updated = false;
|
||||
|
||||
switch ((Buttons)info.ButtonID)
|
||||
{
|
||||
case Buttons.Close:
|
||||
break;
|
||||
case Buttons.Clear:
|
||||
{
|
||||
_Plat = _Gold = 0;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.Accept:
|
||||
{
|
||||
string platText = info.GetTextEntry(0).Text;
|
||||
string goldText = info.GetTextEntry(1).Text;
|
||||
|
||||
if (!int.TryParse(platText, out _Plat))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of platinum.");
|
||||
refresh = true;
|
||||
}
|
||||
else if (!int.TryParse(goldText, out _Gold))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of gold.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalPlat = User.Account.TotalPlat;
|
||||
int totalGold = User.Account.TotalGold;
|
||||
|
||||
if (totalPlat < _Plat || totalGold < _Gold)
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
_Gold = User.Account.TotalGold;
|
||||
User.SendMessage("You do not have that much currency.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check.Plat = _Plat;
|
||||
Check.Gold = _Gold;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Buttons.AllPlat:
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.AllGold:
|
||||
{
|
||||
_Gold = User.Account.TotalGold;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (updated) User.SendMessage("Your offer has been updated.");
|
||||
|
||||
if (refresh && Check != null && !Check.Deleted)
|
||||
{
|
||||
Refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,151 +22,151 @@ using Server.Network;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class BaseHairInfo
|
||||
{
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public int ItemID { get; set; }
|
||||
public abstract class BaseHairInfo
|
||||
{
|
||||
protected BaseHairInfo(int itemid)
|
||||
: this(itemid, 0)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty( AccessLevel.GameMaster )]
|
||||
public int Hue { get; set; }
|
||||
protected BaseHairInfo(int itemid, int hue)
|
||||
{
|
||||
ItemID = itemid;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
protected BaseHairInfo( int itemid )
|
||||
: this( itemid, 0 )
|
||||
{
|
||||
}
|
||||
protected BaseHairInfo(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
protected BaseHairInfo( int itemid, int hue )
|
||||
{
|
||||
ItemID = itemid;
|
||||
Hue = hue;
|
||||
}
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ItemID = reader.ReadInt();
|
||||
Hue = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected BaseHairInfo( GenericReader reader )
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ItemID{ get; set; }
|
||||
|
||||
switch( version )
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ItemID = reader.ReadInt();
|
||||
Hue = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Hue{ get; set; }
|
||||
|
||||
public virtual void Serialize( GenericWriter writer )
|
||||
{
|
||||
writer.Write( (int)0 ); //version
|
||||
writer.Write( (int)ItemID );
|
||||
writer.Write( (int)Hue );
|
||||
}
|
||||
}
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(0); //version
|
||||
writer.Write(ItemID);
|
||||
writer.Write(Hue);
|
||||
}
|
||||
}
|
||||
|
||||
public class HairInfo : BaseHairInfo
|
||||
{
|
||||
public HairInfo( int itemid )
|
||||
: base( itemid, 0 )
|
||||
{
|
||||
}
|
||||
public class HairInfo : BaseHairInfo
|
||||
{
|
||||
public HairInfo(int itemid)
|
||||
: base(itemid, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public HairInfo( int itemid, int hue )
|
||||
: base( itemid, hue )
|
||||
{
|
||||
}
|
||||
public HairInfo(int itemid, int hue)
|
||||
: base(itemid, hue)
|
||||
{
|
||||
}
|
||||
|
||||
public HairInfo( GenericReader reader )
|
||||
: base( reader )
|
||||
{
|
||||
}
|
||||
public HairInfo(GenericReader reader)
|
||||
: base(reader)
|
||||
{
|
||||
}
|
||||
|
||||
public static int FakeSerial( Mobile parent )
|
||||
{
|
||||
return (0x7FFFFFFF - 0x400 - (parent.Serial * 4));
|
||||
}
|
||||
}
|
||||
public static int FakeSerial(Mobile parent)
|
||||
{
|
||||
return 0x7FFFFFFF - 0x400 - parent.Serial * 4;
|
||||
}
|
||||
}
|
||||
|
||||
public class FacialHairInfo : BaseHairInfo
|
||||
{
|
||||
public FacialHairInfo( int itemid )
|
||||
: base( itemid, 0 )
|
||||
{
|
||||
}
|
||||
public class FacialHairInfo : BaseHairInfo
|
||||
{
|
||||
public FacialHairInfo(int itemid)
|
||||
: base(itemid, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public FacialHairInfo( int itemid, int hue )
|
||||
: base( itemid, hue )
|
||||
{
|
||||
}
|
||||
public FacialHairInfo(int itemid, int hue)
|
||||
: base(itemid, hue)
|
||||
{
|
||||
}
|
||||
|
||||
public FacialHairInfo( GenericReader reader )
|
||||
: base( reader )
|
||||
{
|
||||
}
|
||||
public FacialHairInfo(GenericReader reader)
|
||||
: base(reader)
|
||||
{
|
||||
}
|
||||
|
||||
public static int FakeSerial( Mobile parent )
|
||||
{
|
||||
return (0x7FFFFFFF - 0x400 - 1 - (parent.Serial * 4));
|
||||
}
|
||||
}
|
||||
public static int FakeSerial(Mobile parent)
|
||||
{
|
||||
return 0x7FFFFFFF - 0x400 - 1 - parent.Serial * 4;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class HairEquipUpdate : Packet
|
||||
{
|
||||
public HairEquipUpdate( Mobile parent )
|
||||
: base( 0x2E, 15 )
|
||||
{
|
||||
int hue = parent.HairHue;
|
||||
public sealed class HairEquipUpdate : Packet
|
||||
{
|
||||
public HairEquipUpdate(Mobile parent)
|
||||
: base(0x2E, 15)
|
||||
{
|
||||
int hue = parent.HairHue;
|
||||
|
||||
if ( parent.SolidHueOverride >= 0 )
|
||||
hue = parent.SolidHueOverride;
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
|
||||
int hairSerial = HairInfo.FakeSerial( parent );
|
||||
int hairSerial = HairInfo.FakeSerial(parent);
|
||||
|
||||
m_Stream.Write( (int)hairSerial );
|
||||
m_Stream.Write( (short)parent.HairItemID );
|
||||
m_Stream.Write( (byte)0 );
|
||||
m_Stream.Write( (byte)Layer.Hair );
|
||||
m_Stream.Write( (int)parent.Serial );
|
||||
m_Stream.Write( (short)hue );
|
||||
}
|
||||
}
|
||||
m_Stream.Write(hairSerial);
|
||||
m_Stream.Write((short)parent.HairItemID);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write((byte)Layer.Hair);
|
||||
m_Stream.Write(parent.Serial);
|
||||
m_Stream.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class FacialHairEquipUpdate : Packet
|
||||
{
|
||||
public FacialHairEquipUpdate( Mobile parent )
|
||||
: base( 0x2E, 15 )
|
||||
{
|
||||
int hue = parent.FacialHairHue;
|
||||
public sealed class FacialHairEquipUpdate : Packet
|
||||
{
|
||||
public FacialHairEquipUpdate(Mobile parent)
|
||||
: base(0x2E, 15)
|
||||
{
|
||||
int hue = parent.FacialHairHue;
|
||||
|
||||
if ( parent.SolidHueOverride >= 0 )
|
||||
hue = parent.SolidHueOverride;
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
|
||||
int hairSerial = FacialHairInfo.FakeSerial( parent );
|
||||
int hairSerial = FacialHairInfo.FakeSerial(parent);
|
||||
|
||||
m_Stream.Write( (int)hairSerial );
|
||||
m_Stream.Write( (short)parent.FacialHairItemID );
|
||||
m_Stream.Write( (byte)0 );
|
||||
m_Stream.Write( (byte)Layer.FacialHair );
|
||||
m_Stream.Write( (int)parent.Serial );
|
||||
m_Stream.Write( (short)hue );
|
||||
}
|
||||
}
|
||||
m_Stream.Write(hairSerial);
|
||||
m_Stream.Write((short)parent.FacialHairItemID);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write((byte)Layer.FacialHair);
|
||||
m_Stream.Write(parent.Serial);
|
||||
m_Stream.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RemoveHair : Packet
|
||||
{
|
||||
public RemoveHair( Mobile parent )
|
||||
: base( 0x1D, 5 )
|
||||
{
|
||||
m_Stream.Write( (int)HairInfo.FakeSerial( parent ) );
|
||||
}
|
||||
}
|
||||
public sealed class RemoveHair : Packet
|
||||
{
|
||||
public RemoveHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
m_Stream.Write(HairInfo.FakeSerial(parent));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RemoveFacialHair : Packet
|
||||
{
|
||||
public RemoveFacialHair( Mobile parent )
|
||||
: base( 0x1D, 5 )
|
||||
{
|
||||
m_Stream.Write( (int)FacialHairInfo.FakeSerial( parent ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
public sealed class RemoveFacialHair : Packet
|
||||
{
|
||||
public RemoveFacialHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
m_Stream.Write(FacialHairInfo.FakeSerial(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,57 +20,56 @@
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public class KeywordList
|
||||
{
|
||||
private int[] m_Keywords;
|
||||
public class KeywordList
|
||||
{
|
||||
private static int[] m_EmptyInts = new int[0];
|
||||
private int[] m_Keywords;
|
||||
|
||||
public KeywordList()
|
||||
{
|
||||
m_Keywords = new int[8];
|
||||
Count = 0;
|
||||
}
|
||||
public KeywordList()
|
||||
{
|
||||
m_Keywords = new int[8];
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public int Count { get; private set; }
|
||||
public int Count{ get; private set; }
|
||||
|
||||
public bool Contains( int keyword )
|
||||
{
|
||||
bool contains = false;
|
||||
public bool Contains(int keyword)
|
||||
{
|
||||
bool contains = false;
|
||||
|
||||
for ( int i = 0; !contains && i < Count; ++i )
|
||||
contains = ( keyword == m_Keywords[i] );
|
||||
for (int i = 0; !contains && i < Count; ++i)
|
||||
contains = keyword == m_Keywords[i];
|
||||
|
||||
return contains;
|
||||
}
|
||||
return contains;
|
||||
}
|
||||
|
||||
public void Add( int keyword )
|
||||
{
|
||||
if ( (Count + 1) > m_Keywords.Length )
|
||||
{
|
||||
int[] old = m_Keywords;
|
||||
m_Keywords = new int[old.Length * 2];
|
||||
public void Add(int keyword)
|
||||
{
|
||||
if (Count + 1 > m_Keywords.Length)
|
||||
{
|
||||
int[] old = m_Keywords;
|
||||
m_Keywords = new int[old.Length * 2];
|
||||
|
||||
for ( int i = 0; i < old.Length; ++i )
|
||||
m_Keywords[i] = old[i];
|
||||
}
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
m_Keywords[i] = old[i];
|
||||
}
|
||||
|
||||
m_Keywords[Count++] = keyword;
|
||||
}
|
||||
m_Keywords[Count++] = keyword;
|
||||
}
|
||||
|
||||
private static int[] m_EmptyInts = new int[0];
|
||||
public int[] ToArray()
|
||||
{
|
||||
if (Count == 0)
|
||||
return m_EmptyInts;
|
||||
|
||||
public int[] ToArray()
|
||||
{
|
||||
if ( Count == 0 )
|
||||
return m_EmptyInts;
|
||||
int[] keywords = new int[Count];
|
||||
|
||||
int[] keywords = new int[Count];
|
||||
for (int i = 0; i < Count; ++i)
|
||||
keywords[i] = m_Keywords[i];
|
||||
|
||||
for ( int i = 0; i < Count; ++i )
|
||||
keywords[i] = m_Keywords[i];
|
||||
Count = 0;
|
||||
|
||||
Count = 0;
|
||||
|
||||
return keywords;
|
||||
}
|
||||
}
|
||||
return keywords;
|
||||
}
|
||||
}
|
||||
}
|
||||
1189
Server/Main.cs
1189
Server/Main.cs
File diff suppressed because it is too large
Load diff
3009
Server/Map.cs
3009
Server/Map.cs
File diff suppressed because it is too large
Load diff
|
|
@ -22,12 +22,12 @@ using Server.Network;
|
|||
|
||||
namespace Server.Menus
|
||||
{
|
||||
public interface IMenu
|
||||
{
|
||||
int Serial{ get; }
|
||||
int EntryLength{ get; }
|
||||
void SendTo( NetState state );
|
||||
void OnCancel( NetState state );
|
||||
void OnResponse( NetState state, int index );
|
||||
}
|
||||
public interface IMenu
|
||||
{
|
||||
int Serial{ get; }
|
||||
int EntryLength{ get; }
|
||||
void SendTo(NetState state);
|
||||
void OnCancel(NetState state);
|
||||
void OnResponse(NetState state, int index);
|
||||
}
|
||||
}
|
||||
|
|
@ -22,65 +22,65 @@ using Server.Network;
|
|||
|
||||
namespace Server.Menus.ItemLists
|
||||
{
|
||||
public class ItemListEntry
|
||||
{
|
||||
public string Name { get; }
|
||||
public class ItemListEntry
|
||||
{
|
||||
public ItemListEntry(string name, int itemID) : this(name, itemID, 0)
|
||||
{
|
||||
}
|
||||
|
||||
public int ItemID { get; }
|
||||
public ItemListEntry(string name, int itemID, int hue)
|
||||
{
|
||||
Name = name;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
public int Hue { get; }
|
||||
public string Name{ get; }
|
||||
|
||||
public ItemListEntry( string name, int itemID ) : this( name, itemID, 0 )
|
||||
{
|
||||
}
|
||||
public int ItemID{ get; }
|
||||
|
||||
public ItemListEntry( string name, int itemID, int hue )
|
||||
{
|
||||
Name = name;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
}
|
||||
public int Hue{ get; }
|
||||
}
|
||||
|
||||
public class ItemListMenu : IMenu
|
||||
{
|
||||
private int m_Serial;
|
||||
private static int m_NextSerial;
|
||||
public class ItemListMenu : IMenu
|
||||
{
|
||||
private static int m_NextSerial;
|
||||
private int m_Serial;
|
||||
|
||||
int IMenu.Serial => m_Serial;
|
||||
public ItemListMenu(string question, ItemListEntry[] entries)
|
||||
{
|
||||
Question = question;
|
||||
Entries = entries;
|
||||
|
||||
int IMenu.EntryLength => Entries.Length;
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while (m_Serial == 0);
|
||||
|
||||
public string Question { get; }
|
||||
m_Serial = (int)((uint)m_Serial | 0x80000000);
|
||||
}
|
||||
|
||||
public ItemListEntry[] Entries { get; set; }
|
||||
public string Question{ get; }
|
||||
|
||||
public ItemListMenu( string question, ItemListEntry[] entries )
|
||||
{
|
||||
Question = question;
|
||||
Entries = entries;
|
||||
public ItemListEntry[] Entries{ get; set; }
|
||||
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while ( m_Serial == 0 );
|
||||
int IMenu.Serial => m_Serial;
|
||||
|
||||
m_Serial = (int)((uint)m_Serial | 0x80000000);
|
||||
}
|
||||
int IMenu.EntryLength => Entries.Length;
|
||||
|
||||
public virtual void OnCancel( NetState state )
|
||||
{
|
||||
}
|
||||
public virtual void OnCancel(NetState state)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnResponse( NetState state, int index )
|
||||
{
|
||||
}
|
||||
public virtual void OnResponse(NetState state, int index)
|
||||
{
|
||||
}
|
||||
|
||||
public void SendTo( NetState state )
|
||||
{
|
||||
state.AddMenu( this );
|
||||
state.Send( new DisplayItemListMenu( this ) );
|
||||
}
|
||||
}
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.AddMenu(this);
|
||||
state.Send(new DisplayItemListMenu(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,43 +22,43 @@ using Server.Network;
|
|||
|
||||
namespace Server.Menus.Questions
|
||||
{
|
||||
public class QuestionMenu : IMenu
|
||||
{
|
||||
private int m_Serial;
|
||||
private static int m_NextSerial;
|
||||
public class QuestionMenu : IMenu
|
||||
{
|
||||
private static int m_NextSerial;
|
||||
private int m_Serial;
|
||||
|
||||
int IMenu.Serial => m_Serial;
|
||||
public QuestionMenu(string question, string[] answers)
|
||||
{
|
||||
Question = question;
|
||||
Answers = answers;
|
||||
|
||||
int IMenu.EntryLength => Answers.Length;
|
||||
do
|
||||
{
|
||||
m_Serial = ++m_NextSerial;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while (m_Serial == 0);
|
||||
}
|
||||
|
||||
public string Question { get; set; }
|
||||
public string Question{ get; set; }
|
||||
|
||||
public string[] Answers { get; }
|
||||
public string[] Answers{ get; }
|
||||
|
||||
public QuestionMenu( string question, string[] answers )
|
||||
{
|
||||
Question = question;
|
||||
Answers = answers;
|
||||
int IMenu.Serial => m_Serial;
|
||||
|
||||
do
|
||||
{
|
||||
m_Serial = ++m_NextSerial;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while ( m_Serial == 0 );
|
||||
}
|
||||
int IMenu.EntryLength => Answers.Length;
|
||||
|
||||
public virtual void OnCancel( NetState state )
|
||||
{
|
||||
}
|
||||
public virtual void OnCancel(NetState state)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnResponse( NetState state, int index )
|
||||
{
|
||||
}
|
||||
public virtual void OnResponse(NetState state, int index)
|
||||
{
|
||||
}
|
||||
|
||||
public void SendTo( NetState state )
|
||||
{
|
||||
state.AddMenu( this );
|
||||
state.Send( new DisplayQuestionMenu( this ) );
|
||||
}
|
||||
}
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.AddMenu(this);
|
||||
state.Send(new DisplayQuestionMenu(this));
|
||||
}
|
||||
}
|
||||
}
|
||||
20354
Server/Mobile.cs
20354
Server/Mobile.cs
File diff suppressed because it is too large
Load diff
|
|
@ -20,47 +20,67 @@
|
|||
|
||||
namespace Server.Movement
|
||||
{
|
||||
public static class Movement
|
||||
{
|
||||
public static IMovementImpl Impl { get; set; }
|
||||
public static class Movement
|
||||
{
|
||||
public static IMovementImpl Impl{ get; set; }
|
||||
|
||||
public static bool CheckMovement( Mobile m, Direction d, out int newZ )
|
||||
{
|
||||
if ( Impl != null )
|
||||
return Impl.CheckMovement( m, d, out newZ );
|
||||
public static bool CheckMovement(Mobile m, Direction d, out int newZ)
|
||||
{
|
||||
if (Impl != null)
|
||||
return Impl.CheckMovement(m, d, out newZ);
|
||||
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CheckMovement( Mobile m, Map map, Point3D loc, Direction d, out int newZ )
|
||||
{
|
||||
if ( Impl != null )
|
||||
return Impl.CheckMovement( m, map, loc, d, out newZ );
|
||||
public static bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ)
|
||||
{
|
||||
if (Impl != null)
|
||||
return Impl.CheckMovement(m, map, loc, d, out newZ);
|
||||
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Offset( Direction d, ref int x, ref int y )
|
||||
{
|
||||
switch ( d & Direction.Mask )
|
||||
{
|
||||
case Direction.North: --y; break;
|
||||
case Direction.South: ++y; break;
|
||||
case Direction.West: --x; break;
|
||||
case Direction.East: ++x; break;
|
||||
case Direction.Right: ++x; --y; break;
|
||||
case Direction.Left: --x; ++y; break;
|
||||
case Direction.Down: ++x; ++y; break;
|
||||
case Direction.Up: --x; --y; break;
|
||||
}
|
||||
}
|
||||
}
|
||||
public static void Offset(Direction d, ref int x, ref int y)
|
||||
{
|
||||
switch (d & Direction.Mask)
|
||||
{
|
||||
case Direction.North:
|
||||
--y;
|
||||
break;
|
||||
case Direction.South:
|
||||
++y;
|
||||
break;
|
||||
case Direction.West:
|
||||
--x;
|
||||
break;
|
||||
case Direction.East:
|
||||
++x;
|
||||
break;
|
||||
case Direction.Right:
|
||||
++x;
|
||||
--y;
|
||||
break;
|
||||
case Direction.Left:
|
||||
--x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Down:
|
||||
++x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Up:
|
||||
--x;
|
||||
--y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IMovementImpl
|
||||
{
|
||||
bool CheckMovement( Mobile m, Direction d, out int newZ );
|
||||
bool CheckMovement( Mobile m, Map map, Point3D loc, Direction d, out int newZ );
|
||||
}
|
||||
public interface IMovementImpl
|
||||
{
|
||||
bool CheckMovement(Mobile m, Direction d, out int newZ);
|
||||
bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -22,57 +22,62 @@ using System;
|
|||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Server {
|
||||
public static class NativeReader {
|
||||
namespace Server
|
||||
{
|
||||
public static class NativeReader
|
||||
{
|
||||
private static readonly INativeReader m_NativeReader;
|
||||
|
||||
private static readonly INativeReader m_NativeReader;
|
||||
static NativeReader()
|
||||
{
|
||||
if (Core.Unix)
|
||||
m_NativeReader = new NativeReaderUnix();
|
||||
else
|
||||
m_NativeReader = new NativeReaderWin32();
|
||||
}
|
||||
|
||||
static NativeReader() {
|
||||
if ( Core.Unix )
|
||||
m_NativeReader = new NativeReaderUnix();
|
||||
else
|
||||
m_NativeReader = new NativeReaderWin32();
|
||||
}
|
||||
public static unsafe void Read(IntPtr ptr, void* buffer, int length)
|
||||
{
|
||||
m_NativeReader.Read(ptr, buffer, length);
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void Read( IntPtr ptr, void *buffer, int length ) {
|
||||
m_NativeReader.Read( ptr, buffer, length );
|
||||
}
|
||||
}
|
||||
public interface INativeReader
|
||||
{
|
||||
unsafe void Read(IntPtr ptr, void* buffer, int length);
|
||||
}
|
||||
|
||||
public interface INativeReader {
|
||||
unsafe void Read( IntPtr ptr, void *buffer, int length );
|
||||
}
|
||||
public sealed class NativeReaderWin32 : INativeReader
|
||||
{
|
||||
public unsafe void Read(IntPtr ptr, void* buffer, int length)
|
||||
{
|
||||
//UnsafeNativeMethods._lread( ptr, buffer, length );
|
||||
uint lpNumberOfBytesRead = 0;
|
||||
UnsafeNativeMethods.ReadFile(ptr, buffer, (uint)length, ref lpNumberOfBytesRead, null);
|
||||
}
|
||||
|
||||
public sealed class NativeReaderWin32 : INativeReader {
|
||||
internal class UnsafeNativeMethods {
|
||||
/*[DllImport("kernel32")]
|
||||
internal unsafe static extern int _lread(IntPtr hFile, void* lpBuffer, int wBytes);*/
|
||||
internal class UnsafeNativeMethods
|
||||
{
|
||||
/*[DllImport("kernel32")]
|
||||
internal unsafe static extern int _lread(IntPtr hFile, void* lpBuffer, int wBytes);*/
|
||||
|
||||
[DllImport("kernel32")]
|
||||
internal unsafe static extern bool ReadFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToRead, ref uint lpNumberOfBytesRead, NativeOverlapped* lpOverlapped);
|
||||
}
|
||||
[DllImport("kernel32")]
|
||||
internal static extern unsafe bool ReadFile(IntPtr hFile, void* lpBuffer, uint nNumberOfBytesToRead,
|
||||
ref uint lpNumberOfBytesRead, NativeOverlapped* lpOverlapped);
|
||||
}
|
||||
}
|
||||
|
||||
public NativeReaderWin32() {
|
||||
}
|
||||
public sealed class NativeReaderUnix : INativeReader
|
||||
{
|
||||
public unsafe void Read(IntPtr ptr, void* buffer, int length)
|
||||
{
|
||||
UnsafeNativeMethods.read(ptr, buffer, length);
|
||||
}
|
||||
|
||||
public unsafe void Read( IntPtr ptr, void *buffer, int length ) {
|
||||
//UnsafeNativeMethods._lread( ptr, buffer, length );
|
||||
uint lpNumberOfBytesRead = 0;
|
||||
UnsafeNativeMethods.ReadFile(ptr, buffer, (uint)length, ref lpNumberOfBytesRead, null);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NativeReaderUnix : INativeReader {
|
||||
internal class UnsafeNativeMethods {
|
||||
[DllImport("libc")]
|
||||
internal unsafe static extern int read(IntPtr ptr, void* buffer, int length);
|
||||
}
|
||||
|
||||
public NativeReaderUnix() {
|
||||
}
|
||||
|
||||
public unsafe void Read( IntPtr ptr, void *buffer, int length ) {
|
||||
UnsafeNativeMethods.read( ptr, buffer, length );
|
||||
}
|
||||
}
|
||||
internal class UnsafeNativeMethods
|
||||
{
|
||||
[DllImport("libc")]
|
||||
internal static extern unsafe int read(IntPtr ptr, void* buffer, int length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,77 +22,85 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class BufferPool
|
||||
{
|
||||
public static List<BufferPool> Pools { get; set; } = new List<BufferPool>();
|
||||
public class BufferPool
|
||||
{
|
||||
private int m_BufferSize;
|
||||
|
||||
private string m_Name;
|
||||
private Queue<byte[]> m_FreeBuffers;
|
||||
|
||||
private int m_InitialCapacity;
|
||||
private int m_BufferSize;
|
||||
private int m_InitialCapacity;
|
||||
|
||||
private int m_Misses;
|
||||
private int m_Misses;
|
||||
|
||||
private Queue<byte[]> m_FreeBuffers;
|
||||
private string m_Name;
|
||||
|
||||
public void GetInfo( out string name, out int freeCount, out int initialCapacity, out int currentCapacity, out int bufferSize, out int misses )
|
||||
{
|
||||
lock ( this )
|
||||
{
|
||||
name = m_Name;
|
||||
freeCount = m_FreeBuffers.Count;
|
||||
initialCapacity = m_InitialCapacity;
|
||||
currentCapacity = m_InitialCapacity * (1 + m_Misses);
|
||||
bufferSize = m_BufferSize;
|
||||
misses = m_Misses;
|
||||
}
|
||||
}
|
||||
public BufferPool(string name, int initialCapacity, int bufferSize)
|
||||
{
|
||||
m_Name = name;
|
||||
|
||||
public BufferPool( string name, int initialCapacity, int bufferSize )
|
||||
{
|
||||
m_Name = name;
|
||||
m_InitialCapacity = initialCapacity;
|
||||
m_BufferSize = bufferSize;
|
||||
|
||||
m_InitialCapacity = initialCapacity;
|
||||
m_BufferSize = bufferSize;
|
||||
m_FreeBuffers = new Queue<byte[]>(initialCapacity);
|
||||
|
||||
m_FreeBuffers = new Queue<byte[]>( initialCapacity );
|
||||
for (int i = 0; i < initialCapacity; ++i)
|
||||
m_FreeBuffers.Enqueue(new byte[bufferSize]);
|
||||
|
||||
for ( int i = 0; i < initialCapacity; ++i )
|
||||
m_FreeBuffers.Enqueue( new byte[bufferSize] );
|
||||
lock (Pools)
|
||||
{
|
||||
Pools.Add(this);
|
||||
}
|
||||
}
|
||||
|
||||
lock ( Pools )
|
||||
Pools.Add( this );
|
||||
}
|
||||
public static List<BufferPool> Pools{ get; set; } = new List<BufferPool>();
|
||||
|
||||
public byte[] AcquireBuffer()
|
||||
{
|
||||
lock ( this )
|
||||
{
|
||||
if ( m_FreeBuffers.Count > 0 )
|
||||
return m_FreeBuffers.Dequeue();
|
||||
public void GetInfo(out string name, out int freeCount, out int initialCapacity, out int currentCapacity,
|
||||
out int bufferSize, out int misses)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
name = m_Name;
|
||||
freeCount = m_FreeBuffers.Count;
|
||||
initialCapacity = m_InitialCapacity;
|
||||
currentCapacity = m_InitialCapacity * (1 + m_Misses);
|
||||
bufferSize = m_BufferSize;
|
||||
misses = m_Misses;
|
||||
}
|
||||
}
|
||||
|
||||
++m_Misses;
|
||||
public byte[] AcquireBuffer()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (m_FreeBuffers.Count > 0)
|
||||
return m_FreeBuffers.Dequeue();
|
||||
|
||||
for ( int i = 0; i < m_InitialCapacity; ++i )
|
||||
m_FreeBuffers.Enqueue( new byte[m_BufferSize] );
|
||||
++m_Misses;
|
||||
|
||||
return m_FreeBuffers.Dequeue();
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < m_InitialCapacity; ++i)
|
||||
m_FreeBuffers.Enqueue(new byte[m_BufferSize]);
|
||||
|
||||
public void ReleaseBuffer( byte[] buffer )
|
||||
{
|
||||
if ( buffer == null )
|
||||
return;
|
||||
return m_FreeBuffers.Dequeue();
|
||||
}
|
||||
}
|
||||
|
||||
lock ( this )
|
||||
m_FreeBuffers.Enqueue( buffer );
|
||||
}
|
||||
public void ReleaseBuffer(byte[] buffer)
|
||||
{
|
||||
if (buffer == null)
|
||||
return;
|
||||
|
||||
public void Free()
|
||||
{
|
||||
lock ( Pools )
|
||||
Pools.Remove( this );
|
||||
}
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
m_FreeBuffers.Enqueue(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
public void Free()
|
||||
{
|
||||
lock (Pools)
|
||||
{
|
||||
Pools.Remove(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,130 +22,129 @@ using System;
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class ByteQueue
|
||||
{
|
||||
private int m_Head;
|
||||
private int m_Tail;
|
||||
public class ByteQueue
|
||||
{
|
||||
private byte[] m_Buffer;
|
||||
private int m_Head;
|
||||
private int m_Tail;
|
||||
|
||||
private byte[] m_Buffer;
|
||||
public ByteQueue()
|
||||
{
|
||||
m_Buffer = new byte[2048];
|
||||
}
|
||||
|
||||
public int Length { get; private set; }
|
||||
public int Length{ get; private set; }
|
||||
|
||||
public ByteQueue()
|
||||
{
|
||||
m_Buffer = new byte[2048];
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
Length = 0;
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
Length = 0;
|
||||
}
|
||||
private void SetCapacity(int capacity)
|
||||
{
|
||||
byte[] newBuffer = new byte[capacity];
|
||||
|
||||
private void SetCapacity( int capacity )
|
||||
{
|
||||
byte[] newBuffer = new byte[capacity];
|
||||
if (Length > 0)
|
||||
{
|
||||
if (m_Head < m_Tail)
|
||||
{
|
||||
Buffer.BlockCopy(m_Buffer, m_Head, newBuffer, 0, Length);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head);
|
||||
Buffer.BlockCopy(m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail);
|
||||
}
|
||||
}
|
||||
|
||||
if ( Length > 0 )
|
||||
{
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, Length );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, newBuffer, 0, m_Buffer.Length - m_Head );
|
||||
Buffer.BlockCopy( m_Buffer, 0, newBuffer, m_Buffer.Length - m_Head, m_Tail );
|
||||
}
|
||||
}
|
||||
m_Head = 0;
|
||||
m_Tail = Length;
|
||||
m_Buffer = newBuffer;
|
||||
}
|
||||
|
||||
m_Head = 0;
|
||||
m_Tail = Length;
|
||||
m_Buffer = newBuffer;
|
||||
}
|
||||
public byte GetPacketID()
|
||||
{
|
||||
if (Length >= 1)
|
||||
return m_Buffer[m_Head];
|
||||
|
||||
public byte GetPacketID()
|
||||
{
|
||||
if ( Length >= 1 )
|
||||
return m_Buffer[m_Head];
|
||||
return 0xFF;
|
||||
}
|
||||
|
||||
return 0xFF;
|
||||
}
|
||||
public int GetPacketLength()
|
||||
{
|
||||
if (Length >= 3)
|
||||
return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length];
|
||||
|
||||
public int GetPacketLength()
|
||||
{
|
||||
if ( Length >= 3 )
|
||||
return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length];
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
public int Dequeue(byte[] buffer, int offset, int size)
|
||||
{
|
||||
if (size > Length)
|
||||
size = Length;
|
||||
|
||||
public int Dequeue( byte[] buffer, int offset, int size )
|
||||
{
|
||||
if ( size > Length )
|
||||
size = Length;
|
||||
if (size == 0)
|
||||
return 0;
|
||||
|
||||
if ( size == 0 )
|
||||
return 0;
|
||||
if (m_Head < m_Tail)
|
||||
{
|
||||
Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
int rightLength = m_Buffer.Length - m_Head;
|
||||
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
int rightLength = ( m_Buffer.Length - m_Head );
|
||||
if (rightLength >= size)
|
||||
{
|
||||
Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(m_Buffer, m_Head, buffer, offset, rightLength);
|
||||
Buffer.BlockCopy(m_Buffer, 0, buffer, offset + rightLength, size - rightLength);
|
||||
}
|
||||
}
|
||||
|
||||
if ( rightLength >= size )
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( m_Buffer, m_Head, buffer, offset, rightLength );
|
||||
Buffer.BlockCopy( m_Buffer, 0, buffer, offset + rightLength, size - rightLength );
|
||||
}
|
||||
}
|
||||
m_Head = (m_Head + size) % m_Buffer.Length;
|
||||
Length -= size;
|
||||
|
||||
m_Head = ( m_Head + size ) % m_Buffer.Length;
|
||||
Length -= size;
|
||||
if (Length == 0)
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
}
|
||||
|
||||
if ( Length == 0 )
|
||||
{
|
||||
m_Head = 0;
|
||||
m_Tail = 0;
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
return size;
|
||||
}
|
||||
public void Enqueue(byte[] buffer, int offset, int size)
|
||||
{
|
||||
if (Length + size > m_Buffer.Length)
|
||||
SetCapacity((Length + size + 2047) & ~2047);
|
||||
|
||||
public void Enqueue( byte[] buffer, int offset, int size )
|
||||
{
|
||||
if ( (Length + size) > m_Buffer.Length )
|
||||
SetCapacity( (Length + size + 2047) & ~2047 );
|
||||
if (m_Head < m_Tail)
|
||||
{
|
||||
int rightLength = m_Buffer.Length - m_Tail;
|
||||
|
||||
if ( m_Head < m_Tail )
|
||||
{
|
||||
int rightLength = ( m_Buffer.Length - m_Tail );
|
||||
if (rightLength >= size)
|
||||
{
|
||||
Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, size);
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, rightLength);
|
||||
Buffer.BlockCopy(buffer, offset + rightLength, m_Buffer, 0, size - rightLength);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy(buffer, offset, m_Buffer, m_Tail, size);
|
||||
}
|
||||
|
||||
if ( rightLength >= size )
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, rightLength );
|
||||
Buffer.BlockCopy( buffer, offset + rightLength, m_Buffer, 0, size - rightLength );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Buffer.BlockCopy( buffer, offset, m_Buffer, m_Tail, size );
|
||||
}
|
||||
|
||||
m_Tail = ( m_Tail + size ) % m_Buffer.Length;
|
||||
Length += size;
|
||||
}
|
||||
}
|
||||
m_Tail = (m_Tail + size) % m_Buffer.Length;
|
||||
Length += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,371 +21,379 @@
|
|||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Server.Network {
|
||||
/// <summary>
|
||||
/// Handles outgoing packet compression for the network.
|
||||
/// </summary>
|
||||
public static class Compression {
|
||||
private static int[] _huffmanTable = new int[514]
|
||||
{
|
||||
0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032,
|
||||
0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057,
|
||||
0x8, 0x071, 0x8, 0x05B, 0x9, 0x1CC, 0x8, 0x0A7, 0x7, 0x025, 0x7, 0x04F, 0x8, 0x066, 0x8, 0x07D,
|
||||
0x9, 0x191, 0x9, 0x1CE, 0x7, 0x03F, 0x9, 0x090, 0x8, 0x059, 0x8, 0x07B, 0x8, 0x091, 0x8, 0x0C6,
|
||||
0x6, 0x02D, 0x9, 0x186, 0x8, 0x06F, 0x9, 0x093, 0xA, 0x1CC, 0x8, 0x05A, 0xA, 0x1AE, 0xA, 0x1C0,
|
||||
0x9, 0x148, 0x9, 0x14A, 0x9, 0x082, 0xA, 0x19F, 0x9, 0x171, 0x9, 0x120, 0x9, 0x0E7, 0xA, 0x1F3,
|
||||
0x9, 0x14B, 0x9, 0x100, 0x9, 0x190, 0x6, 0x013, 0x9, 0x161, 0x9, 0x125, 0x9, 0x133, 0x9, 0x195,
|
||||
0x9, 0x173, 0x9, 0x1CA, 0x9, 0x086, 0x9, 0x1E9, 0x9, 0x0DB, 0x9, 0x1EC, 0x9, 0x08B, 0x9, 0x085,
|
||||
0x5, 0x00A, 0x8, 0x096, 0x8, 0x09C, 0x9, 0x1C3, 0x9, 0x19C, 0x9, 0x08F, 0x9, 0x18F, 0x9, 0x091,
|
||||
0x9, 0x087, 0x9, 0x0C6, 0x9, 0x177, 0x9, 0x089, 0x9, 0x0D6, 0x9, 0x08C, 0x9, 0x1EE, 0x9, 0x1EB,
|
||||
0x9, 0x084, 0x9, 0x164, 0x9, 0x175, 0x9, 0x1CD, 0x8, 0x05E, 0x9, 0x088, 0x9, 0x12B, 0x9, 0x172,
|
||||
0x9, 0x10A, 0x9, 0x08D, 0x9, 0x13A, 0x9, 0x11C, 0xA, 0x1E1, 0xA, 0x1E0, 0x9, 0x187, 0xA, 0x1DC,
|
||||
0xA, 0x1DF, 0x7, 0x074, 0x9, 0x19F, 0x8, 0x08D, 0x8, 0x0E4, 0x7, 0x079, 0x9, 0x0EA, 0x9, 0x0E1,
|
||||
0x8, 0x040, 0x7, 0x041, 0x9, 0x10B, 0x9, 0x0B0, 0x8, 0x06A, 0x8, 0x0C1, 0x7, 0x071, 0x7, 0x078,
|
||||
0x8, 0x0B1, 0x9, 0x14C, 0x7, 0x043, 0x8, 0x076, 0x7, 0x066, 0x7, 0x04D, 0x9, 0x08A, 0x6, 0x02F,
|
||||
0x8, 0x0C9, 0x9, 0x0CE, 0x9, 0x149, 0x9, 0x160, 0xA, 0x1BA, 0xA, 0x19E, 0xA, 0x39F, 0x9, 0x0E5,
|
||||
0x9, 0x194, 0x9, 0x184, 0x9, 0x126, 0x7, 0x030, 0x8, 0x06C, 0x9, 0x121, 0x9, 0x1E8, 0xA, 0x1C1,
|
||||
0xA, 0x11D, 0xA, 0x163, 0xA, 0x385, 0xA, 0x3DB, 0xA, 0x17D, 0xA, 0x106, 0xA, 0x397, 0xA, 0x24E,
|
||||
0x7, 0x02E, 0x8, 0x098, 0xA, 0x33C, 0xA, 0x32E, 0xA, 0x1E9, 0x9, 0x0BF, 0xA, 0x3DF, 0xA, 0x1DD,
|
||||
0xA, 0x32D, 0xA, 0x2ED, 0xA, 0x30B, 0xA, 0x107, 0xA, 0x2E8, 0xA, 0x3DE, 0xA, 0x125, 0xA, 0x1E8,
|
||||
0x9, 0x0E9, 0xA, 0x1CD, 0xA, 0x1B5, 0x9, 0x165, 0xA, 0x232, 0xA, 0x2E1, 0xB, 0x3AE, 0xB, 0x3C6,
|
||||
0xB, 0x3E2, 0xA, 0x205, 0xA, 0x29A, 0xA, 0x248, 0xA, 0x2CD, 0xA, 0x23B, 0xB, 0x3C5, 0xA, 0x251,
|
||||
0xA, 0x2E9, 0xA, 0x252, 0x9, 0x1EA, 0xB, 0x3A0, 0xB, 0x391, 0xA, 0x23C, 0xB, 0x392, 0xB, 0x3D5,
|
||||
0xA, 0x233, 0xA, 0x2CC, 0xB, 0x390, 0xA, 0x1BB, 0xB, 0x3A1, 0xB, 0x3C4, 0xA, 0x211, 0xA, 0x203,
|
||||
0x9, 0x12A, 0xA, 0x231, 0xB, 0x3E0, 0xA, 0x29B, 0xB, 0x3D7, 0xA, 0x202, 0xB, 0x3AD, 0xA, 0x213,
|
||||
0xA, 0x253, 0xA, 0x32C, 0xA, 0x23D, 0xA, 0x23F, 0xA, 0x32F, 0xA, 0x11C, 0xA, 0x384, 0xA, 0x31C,
|
||||
0xA, 0x17C, 0xA, 0x30A, 0xA, 0x2E0, 0xA, 0x276, 0xA, 0x250, 0xB, 0x3E3, 0xA, 0x396, 0xA, 0x18F,
|
||||
0xA, 0x204, 0xA, 0x206, 0xA, 0x230, 0xA, 0x265, 0xA, 0x212, 0xA, 0x23E, 0xB, 0x3AC, 0xB, 0x393,
|
||||
0xB, 0x3E1, 0xA, 0x1DE, 0xB, 0x3D6, 0xA, 0x31D, 0xB, 0x3E5, 0xB, 0x3E4, 0xA, 0x207, 0xB, 0x3C7,
|
||||
0xA, 0x277, 0xB, 0x3D4, 0x8, 0x0C0, 0xA, 0x162, 0xA, 0x3DA, 0xA, 0x124, 0xA, 0x1B4, 0xA, 0x264,
|
||||
0xA, 0x33D, 0xA, 0x1D1, 0xA, 0x1AF, 0xA, 0x39E, 0xA, 0x24F, 0xB, 0x373, 0xA, 0x249, 0xB, 0x372,
|
||||
0x9, 0x167, 0xA, 0x210, 0xA, 0x23A, 0xA, 0x1B8, 0xB, 0x3AF, 0xA, 0x18E, 0xA, 0x2EC, 0x7, 0x062,
|
||||
0x4, 0x00D
|
||||
};
|
||||
|
||||
private const int CountIndex = 0;
|
||||
private const int ValueIndex = 1;
|
||||
|
||||
// UO packets may not exceed 64kb in length
|
||||
private const int BufferSize = 0x10000;
|
||||
|
||||
// Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8
|
||||
private const int MinimalCodeLength = 2;
|
||||
private const int MaximalCodeLength = 11;
|
||||
|
||||
// Fixed overhead, in bits, per compression call
|
||||
private const int TerminalCodeLength = 4;
|
||||
|
||||
// If our input exceeds this length, we cannot possibly compress it within the buffer
|
||||
private const int DefiniteOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MinimalCodeLength;
|
||||
|
||||
// If our input exceeds this length, we may potentially overflow the buffer
|
||||
private const int PossibleOverflow = ( ( BufferSize * 8 ) - TerminalCodeLength ) / MaximalCodeLength;
|
||||
|
||||
public unsafe static void Compress(byte[] input, int offset, int count, byte[] output, ref int length)
|
||||
{
|
||||
if (input == null)
|
||||
{
|
||||
throw new ArgumentNullException("input");
|
||||
}
|
||||
|
||||
if (offset < 0 || offset >= input.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("offset");
|
||||
}
|
||||
if (count < 0 || count > input.Length)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException("count");
|
||||
}
|
||||
if ((input.Length - offset) < count)
|
||||
{
|
||||
throw new ArgumentException();
|
||||
}
|
||||
|
||||
length = 0;
|
||||
|
||||
if (count > DefiniteOverflow)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
int bitCount = 0;
|
||||
int bitValue = 0;
|
||||
|
||||
fixed (int* pTable = _huffmanTable)
|
||||
{
|
||||
int* pEntry;
|
||||
|
||||
fixed (byte* pInputBuffer = input)
|
||||
{
|
||||
byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count;
|
||||
|
||||
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
|
||||
{
|
||||
length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static readonly ICompressor Compressor;
|
||||
|
||||
static Compression() {
|
||||
if ( Core.Unix ) {
|
||||
if ( Core.Is64Bit ) {
|
||||
Compressor = new CompressorUnix64();
|
||||
} else {
|
||||
Compressor = new CompressorUnix32();
|
||||
}
|
||||
} else if ( Core.Is64Bit ) {
|
||||
Compressor = new Compressor64();
|
||||
} else {
|
||||
Compressor = new Compressor32();
|
||||
}
|
||||
}
|
||||
|
||||
public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return Compressor.Compress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
|
||||
public static ZLibError Pack( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
|
||||
return Compressor.Compress( dest, ref destLength, source, sourceLength, quality );
|
||||
}
|
||||
|
||||
public static ZLibError Unpack( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return Compressor.Decompress( dest, ref destLength, source, sourceLength );
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICompressor {
|
||||
string Version {
|
||||
get;
|
||||
}
|
||||
|
||||
ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality );
|
||||
|
||||
ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength );
|
||||
}
|
||||
|
||||
public sealed class Compressor32 : ICompressor {
|
||||
internal class SafeNativeMethods {
|
||||
[DllImport( "zlib32" )]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
[DllImport( "zlib32" )]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
|
||||
public Compressor32() {
|
||||
}
|
||||
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Compressor64 : ICompressor {
|
||||
internal class SafeNativeMethods {
|
||||
[DllImport("zlib64")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
|
||||
public Compressor64() {
|
||||
}
|
||||
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix32 : ICompressor {
|
||||
internal class SafeNativeMethods {
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
|
||||
public CompressorUnix32() {
|
||||
}
|
||||
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix64 : ICompressor {
|
||||
internal class SafeNativeMethods {
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref ulong destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref ulong destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref ulong destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
|
||||
public CompressorUnix64() {
|
||||
}
|
||||
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Compress( byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality ) {
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress2(dest, ref destLengthLong, source, sourceLength, quality);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Decompress( byte[] dest, ref int destLength, byte[] source, int sourceLength ) {
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.uncompress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
}
|
||||
|
||||
public enum ZLibError : int {
|
||||
VersionError = -6,
|
||||
BufferError = -5,
|
||||
MemoryError = -4,
|
||||
DataError = -3,
|
||||
StreamError = -2,
|
||||
FileError = -1,
|
||||
|
||||
Okay = 0,
|
||||
|
||||
StreamEnd = 1,
|
||||
NeedDictionary = 2
|
||||
}
|
||||
|
||||
public enum ZLibQuality : int {
|
||||
Default = -1,
|
||||
|
||||
None = 0,
|
||||
|
||||
Speed = 1,
|
||||
Size = 9
|
||||
}
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles outgoing packet compression for the network.
|
||||
/// </summary>
|
||||
public static class Compression
|
||||
{
|
||||
private const int CountIndex = 0;
|
||||
private const int ValueIndex = 1;
|
||||
|
||||
// UO packets may not exceed 64kb in length
|
||||
private const int BufferSize = 0x10000;
|
||||
|
||||
// Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8
|
||||
private const int MinimalCodeLength = 2;
|
||||
private const int MaximalCodeLength = 11;
|
||||
|
||||
// Fixed overhead, in bits, per compression call
|
||||
private const int TerminalCodeLength = 4;
|
||||
|
||||
// If our input exceeds this length, we cannot possibly compress it within the buffer
|
||||
private const int DefiniteOverflow = (BufferSize * 8 - TerminalCodeLength) / MinimalCodeLength;
|
||||
|
||||
// If our input exceeds this length, we may potentially overflow the buffer
|
||||
private const int PossibleOverflow = (BufferSize * 8 - TerminalCodeLength) / MaximalCodeLength;
|
||||
|
||||
private static int[] _huffmanTable = new int[514]
|
||||
{
|
||||
0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032,
|
||||
0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057,
|
||||
0x8, 0x071, 0x8, 0x05B, 0x9, 0x1CC, 0x8, 0x0A7, 0x7, 0x025, 0x7, 0x04F, 0x8, 0x066, 0x8, 0x07D,
|
||||
0x9, 0x191, 0x9, 0x1CE, 0x7, 0x03F, 0x9, 0x090, 0x8, 0x059, 0x8, 0x07B, 0x8, 0x091, 0x8, 0x0C6,
|
||||
0x6, 0x02D, 0x9, 0x186, 0x8, 0x06F, 0x9, 0x093, 0xA, 0x1CC, 0x8, 0x05A, 0xA, 0x1AE, 0xA, 0x1C0,
|
||||
0x9, 0x148, 0x9, 0x14A, 0x9, 0x082, 0xA, 0x19F, 0x9, 0x171, 0x9, 0x120, 0x9, 0x0E7, 0xA, 0x1F3,
|
||||
0x9, 0x14B, 0x9, 0x100, 0x9, 0x190, 0x6, 0x013, 0x9, 0x161, 0x9, 0x125, 0x9, 0x133, 0x9, 0x195,
|
||||
0x9, 0x173, 0x9, 0x1CA, 0x9, 0x086, 0x9, 0x1E9, 0x9, 0x0DB, 0x9, 0x1EC, 0x9, 0x08B, 0x9, 0x085,
|
||||
0x5, 0x00A, 0x8, 0x096, 0x8, 0x09C, 0x9, 0x1C3, 0x9, 0x19C, 0x9, 0x08F, 0x9, 0x18F, 0x9, 0x091,
|
||||
0x9, 0x087, 0x9, 0x0C6, 0x9, 0x177, 0x9, 0x089, 0x9, 0x0D6, 0x9, 0x08C, 0x9, 0x1EE, 0x9, 0x1EB,
|
||||
0x9, 0x084, 0x9, 0x164, 0x9, 0x175, 0x9, 0x1CD, 0x8, 0x05E, 0x9, 0x088, 0x9, 0x12B, 0x9, 0x172,
|
||||
0x9, 0x10A, 0x9, 0x08D, 0x9, 0x13A, 0x9, 0x11C, 0xA, 0x1E1, 0xA, 0x1E0, 0x9, 0x187, 0xA, 0x1DC,
|
||||
0xA, 0x1DF, 0x7, 0x074, 0x9, 0x19F, 0x8, 0x08D, 0x8, 0x0E4, 0x7, 0x079, 0x9, 0x0EA, 0x9, 0x0E1,
|
||||
0x8, 0x040, 0x7, 0x041, 0x9, 0x10B, 0x9, 0x0B0, 0x8, 0x06A, 0x8, 0x0C1, 0x7, 0x071, 0x7, 0x078,
|
||||
0x8, 0x0B1, 0x9, 0x14C, 0x7, 0x043, 0x8, 0x076, 0x7, 0x066, 0x7, 0x04D, 0x9, 0x08A, 0x6, 0x02F,
|
||||
0x8, 0x0C9, 0x9, 0x0CE, 0x9, 0x149, 0x9, 0x160, 0xA, 0x1BA, 0xA, 0x19E, 0xA, 0x39F, 0x9, 0x0E5,
|
||||
0x9, 0x194, 0x9, 0x184, 0x9, 0x126, 0x7, 0x030, 0x8, 0x06C, 0x9, 0x121, 0x9, 0x1E8, 0xA, 0x1C1,
|
||||
0xA, 0x11D, 0xA, 0x163, 0xA, 0x385, 0xA, 0x3DB, 0xA, 0x17D, 0xA, 0x106, 0xA, 0x397, 0xA, 0x24E,
|
||||
0x7, 0x02E, 0x8, 0x098, 0xA, 0x33C, 0xA, 0x32E, 0xA, 0x1E9, 0x9, 0x0BF, 0xA, 0x3DF, 0xA, 0x1DD,
|
||||
0xA, 0x32D, 0xA, 0x2ED, 0xA, 0x30B, 0xA, 0x107, 0xA, 0x2E8, 0xA, 0x3DE, 0xA, 0x125, 0xA, 0x1E8,
|
||||
0x9, 0x0E9, 0xA, 0x1CD, 0xA, 0x1B5, 0x9, 0x165, 0xA, 0x232, 0xA, 0x2E1, 0xB, 0x3AE, 0xB, 0x3C6,
|
||||
0xB, 0x3E2, 0xA, 0x205, 0xA, 0x29A, 0xA, 0x248, 0xA, 0x2CD, 0xA, 0x23B, 0xB, 0x3C5, 0xA, 0x251,
|
||||
0xA, 0x2E9, 0xA, 0x252, 0x9, 0x1EA, 0xB, 0x3A0, 0xB, 0x391, 0xA, 0x23C, 0xB, 0x392, 0xB, 0x3D5,
|
||||
0xA, 0x233, 0xA, 0x2CC, 0xB, 0x390, 0xA, 0x1BB, 0xB, 0x3A1, 0xB, 0x3C4, 0xA, 0x211, 0xA, 0x203,
|
||||
0x9, 0x12A, 0xA, 0x231, 0xB, 0x3E0, 0xA, 0x29B, 0xB, 0x3D7, 0xA, 0x202, 0xB, 0x3AD, 0xA, 0x213,
|
||||
0xA, 0x253, 0xA, 0x32C, 0xA, 0x23D, 0xA, 0x23F, 0xA, 0x32F, 0xA, 0x11C, 0xA, 0x384, 0xA, 0x31C,
|
||||
0xA, 0x17C, 0xA, 0x30A, 0xA, 0x2E0, 0xA, 0x276, 0xA, 0x250, 0xB, 0x3E3, 0xA, 0x396, 0xA, 0x18F,
|
||||
0xA, 0x204, 0xA, 0x206, 0xA, 0x230, 0xA, 0x265, 0xA, 0x212, 0xA, 0x23E, 0xB, 0x3AC, 0xB, 0x393,
|
||||
0xB, 0x3E1, 0xA, 0x1DE, 0xB, 0x3D6, 0xA, 0x31D, 0xB, 0x3E5, 0xB, 0x3E4, 0xA, 0x207, 0xB, 0x3C7,
|
||||
0xA, 0x277, 0xB, 0x3D4, 0x8, 0x0C0, 0xA, 0x162, 0xA, 0x3DA, 0xA, 0x124, 0xA, 0x1B4, 0xA, 0x264,
|
||||
0xA, 0x33D, 0xA, 0x1D1, 0xA, 0x1AF, 0xA, 0x39E, 0xA, 0x24F, 0xB, 0x373, 0xA, 0x249, 0xB, 0x372,
|
||||
0x9, 0x167, 0xA, 0x210, 0xA, 0x23A, 0xA, 0x1B8, 0xB, 0x3AF, 0xA, 0x18E, 0xA, 0x2EC, 0x7, 0x062,
|
||||
0x4, 0x00D
|
||||
};
|
||||
|
||||
public static readonly ICompressor Compressor;
|
||||
|
||||
static Compression()
|
||||
{
|
||||
if (Core.Unix)
|
||||
{
|
||||
if (Core.Is64Bit)
|
||||
Compressor = new CompressorUnix64();
|
||||
else
|
||||
Compressor = new CompressorUnix32();
|
||||
}
|
||||
else if (Core.Is64Bit)
|
||||
{
|
||||
Compressor = new Compressor64();
|
||||
}
|
||||
else
|
||||
{
|
||||
Compressor = new Compressor32();
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void Compress(byte[] input, int offset, int count, byte[] output, ref int length)
|
||||
{
|
||||
if (input == null) throw new ArgumentNullException("input");
|
||||
|
||||
if (offset < 0 || offset >= input.Length) throw new ArgumentOutOfRangeException("offset");
|
||||
if (count < 0 || count > input.Length) throw new ArgumentOutOfRangeException("count");
|
||||
if (input.Length - offset < count) throw new ArgumentException();
|
||||
|
||||
length = 0;
|
||||
|
||||
if (count > DefiniteOverflow) return;
|
||||
|
||||
int bitCount = 0;
|
||||
int bitValue = 0;
|
||||
|
||||
fixed (int* pTable = _huffmanTable)
|
||||
{
|
||||
int* pEntry;
|
||||
|
||||
fixed (byte* pInputBuffer = input)
|
||||
{
|
||||
byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count;
|
||||
|
||||
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
|
||||
{
|
||||
length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ZLibError Pack(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return Compressor.Compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public static ZLibError Pack(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return Compressor.Compress(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public static ZLibError Unpack(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return Compressor.Decompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICompressor
|
||||
{
|
||||
string Version{ get; }
|
||||
|
||||
ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
}
|
||||
|
||||
public sealed class Compressor32 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("zlib32")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Compressor64 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("zlib64")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix32 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix64 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress2(dest, ref destLengthLong, source, sourceLength, quality);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.uncompress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref ulong destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref ulong destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref ulong destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ZLibError
|
||||
{
|
||||
VersionError = -6,
|
||||
BufferError = -5,
|
||||
MemoryError = -4,
|
||||
DataError = -3,
|
||||
StreamError = -2,
|
||||
FileError = -1,
|
||||
|
||||
Okay = 0,
|
||||
|
||||
StreamEnd = 1,
|
||||
NeedDictionary = 2
|
||||
}
|
||||
|
||||
public enum ZLibQuality
|
||||
{
|
||||
Default = -1,
|
||||
|
||||
None = 0,
|
||||
|
||||
Speed = 1,
|
||||
Size = 9
|
||||
}
|
||||
}
|
||||
|
|
@ -20,21 +20,21 @@
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public delegate void OnEncodedPacketReceive( NetState state, IEntity ent, EncodedReader pvSrc );
|
||||
public delegate void OnEncodedPacketReceive(NetState state, IEntity ent, EncodedReader pvSrc);
|
||||
|
||||
public class EncodedPacketHandler
|
||||
{
|
||||
public EncodedPacketHandler( int packetID, bool ingame, OnEncodedPacketReceive onReceive )
|
||||
{
|
||||
PacketID = packetID;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
public class EncodedPacketHandler
|
||||
{
|
||||
public EncodedPacketHandler(int packetID, bool ingame, OnEncodedPacketReceive onReceive)
|
||||
{
|
||||
PacketID = packetID;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int PacketID { get; }
|
||||
public int PacketID{ get; }
|
||||
|
||||
public OnEncodedPacketReceive OnReceive { get; }
|
||||
public OnEncodedPacketReceive OnReceive{ get; }
|
||||
|
||||
public bool Ingame { get; }
|
||||
}
|
||||
public bool Ingame{ get; }
|
||||
}
|
||||
}
|
||||
|
|
@ -20,56 +20,56 @@
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class EncodedReader
|
||||
{
|
||||
private PacketReader m_Reader;
|
||||
public class EncodedReader
|
||||
{
|
||||
private PacketReader m_Reader;
|
||||
|
||||
public EncodedReader( PacketReader reader )
|
||||
{
|
||||
m_Reader = reader;
|
||||
}
|
||||
public EncodedReader(PacketReader reader)
|
||||
{
|
||||
m_Reader = reader;
|
||||
}
|
||||
|
||||
public byte[] Buffer => m_Reader.Buffer;
|
||||
public byte[] Buffer => m_Reader.Buffer;
|
||||
|
||||
public void Trace( NetState state )
|
||||
{
|
||||
m_Reader.Trace( state );
|
||||
}
|
||||
public void Trace(NetState state)
|
||||
{
|
||||
m_Reader.Trace(state);
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 0 )
|
||||
return 0;
|
||||
public int ReadInt32()
|
||||
{
|
||||
if (m_Reader.ReadByte() != 0)
|
||||
return 0;
|
||||
|
||||
return m_Reader.ReadInt32();
|
||||
}
|
||||
return m_Reader.ReadInt32();
|
||||
}
|
||||
|
||||
public Point3D ReadPoint3D()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 3 )
|
||||
return Point3D.Zero;
|
||||
public Point3D ReadPoint3D()
|
||||
{
|
||||
if (m_Reader.ReadByte() != 3)
|
||||
return Point3D.Zero;
|
||||
|
||||
return new Point3D( m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte() );
|
||||
}
|
||||
return new Point3D(m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte());
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 2 )
|
||||
return "";
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
if (m_Reader.ReadByte() != 2)
|
||||
return "";
|
||||
|
||||
int length = m_Reader.ReadUInt16();
|
||||
int length = m_Reader.ReadUInt16();
|
||||
|
||||
return m_Reader.ReadUnicodeStringSafe( length );
|
||||
}
|
||||
return m_Reader.ReadUnicodeStringSafe(length);
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
if ( m_Reader.ReadByte() != 2 )
|
||||
return "";
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
if (m_Reader.ReadByte() != 2)
|
||||
return "";
|
||||
|
||||
int length = m_Reader.ReadUInt16();
|
||||
int length = m_Reader.ReadUInt16();
|
||||
|
||||
return m_Reader.ReadUnicodeString( length );
|
||||
}
|
||||
}
|
||||
return m_Reader.ReadUnicodeString(length);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -28,39 +28,39 @@ using System.Threading;
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class Listener : IDisposable
|
||||
{
|
||||
private Socket m_Listener;
|
||||
public class Listener : IDisposable
|
||||
{
|
||||
private Socket m_Listener;
|
||||
|
||||
private Queue<Socket> m_Accepted;
|
||||
private object m_AcceptedSyncRoot;
|
||||
private Queue<Socket> m_Accepted;
|
||||
private object m_AcceptedSyncRoot;
|
||||
|
||||
#if NewAsyncSockets
|
||||
private SocketAsyncEventArgs m_EventArgs;
|
||||
private SocketAsyncEventArgs m_EventArgs;
|
||||
#else
|
||||
private AsyncCallback m_OnAccept;
|
||||
#endif
|
||||
|
||||
private static Socket[] m_EmptySockets = new Socket[0];
|
||||
private static Socket[] m_EmptySockets = new Socket[0];
|
||||
|
||||
public static IPEndPoint[] EndPoints { get; set; }
|
||||
public static IPEndPoint[] EndPoints{ get; set; }
|
||||
|
||||
public Listener( IPEndPoint ipep )
|
||||
{
|
||||
m_Accepted = new Queue<Socket>();
|
||||
m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot;
|
||||
public Listener(IPEndPoint ipep)
|
||||
{
|
||||
m_Accepted = new Queue<Socket>();
|
||||
m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot;
|
||||
|
||||
m_Listener = Bind( ipep );
|
||||
m_Listener = Bind(ipep);
|
||||
|
||||
if ( m_Listener == null )
|
||||
return;
|
||||
if (m_Listener == null)
|
||||
return;
|
||||
|
||||
DisplayListener();
|
||||
DisplayListener();
|
||||
|
||||
#if NewAsyncSockets
|
||||
m_EventArgs = new SocketAsyncEventArgs();
|
||||
m_EventArgs.Completed += Accept_Completion;
|
||||
Accept_Start();
|
||||
m_EventArgs = new SocketAsyncEventArgs();
|
||||
m_EventArgs.Completed += Accept_Completion;
|
||||
Accept_Start();
|
||||
#else
|
||||
m_OnAccept = new AsyncCallback( OnAccept );
|
||||
try {
|
||||
|
|
@ -70,111 +70,124 @@ namespace Server.Network
|
|||
} catch ( ObjectDisposedException ) {
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
private Socket Bind( IPEndPoint ipep )
|
||||
{
|
||||
Socket s = new Socket( ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp );
|
||||
private Socket Bind(IPEndPoint ipep)
|
||||
{
|
||||
Socket s = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
|
||||
try
|
||||
{
|
||||
s.LingerState.Enabled = false;
|
||||
s.ExclusiveAddressUse = false;
|
||||
try
|
||||
{
|
||||
s.LingerState.Enabled = false;
|
||||
s.ExclusiveAddressUse = false;
|
||||
|
||||
s.Bind( ipep );
|
||||
s.Listen( 8 );
|
||||
s.Bind(ipep);
|
||||
s.Listen(8);
|
||||
|
||||
return s;
|
||||
}
|
||||
catch ( Exception e )
|
||||
{
|
||||
if ( e is SocketException se ) {
|
||||
if ( se.ErrorCode == 10048 ) { // WSAEADDRINUSE
|
||||
Console.WriteLine( "Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port );
|
||||
}
|
||||
else if ( se.ErrorCode == 10049 ) { // WSAEADDRNOTAVAIL
|
||||
Console.WriteLine( "Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port );
|
||||
}
|
||||
else {
|
||||
Console.WriteLine( "Listener Exception:" );
|
||||
Console.WriteLine( e );
|
||||
}
|
||||
}
|
||||
return s;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is SocketException se)
|
||||
{
|
||||
if (se.ErrorCode == 10048)
|
||||
{
|
||||
// WSAEADDRINUSE
|
||||
Console.WriteLine("Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port);
|
||||
}
|
||||
else if (se.ErrorCode == 10049)
|
||||
{
|
||||
// WSAEADDRNOTAVAIL
|
||||
Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Listener Exception:");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayListener()
|
||||
{
|
||||
if ( !(m_Listener.LocalEndPoint is IPEndPoint ipep) )
|
||||
return;
|
||||
private void DisplayListener()
|
||||
{
|
||||
if (!(m_Listener.LocalEndPoint is IPEndPoint ipep))
|
||||
return;
|
||||
|
||||
if ( ipep.Address.Equals( IPAddress.Any ) || ipep.Address.Equals( IPAddress.IPv6Any ) ) {
|
||||
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach ( NetworkInterface adapter in adapters ) {
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
foreach ( UnicastIPAddressInformation unicast in properties.UnicastAddresses ) {
|
||||
if ( ipep.AddressFamily == unicast.Address.AddressFamily )
|
||||
Console.WriteLine( "Listening: {0}:{1}", unicast.Address, ipep.Port );
|
||||
}
|
||||
}
|
||||
/*
|
||||
try {
|
||||
Console.WriteLine( "Listening: {0}:{1}", IPAddress.Loopback, ipep.Port );
|
||||
IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() );
|
||||
IPAddress[] ip = iphe.AddressList;
|
||||
for ( int i = 0; i < ip.Length; ++i )
|
||||
Console.WriteLine( "Listening: {0}:{1}", ip[i], ipep.Port );
|
||||
}
|
||||
catch { }
|
||||
*/
|
||||
}
|
||||
else {
|
||||
Console.WriteLine( "Listening: {0}:{1}", ipep.Address, ipep.Port );
|
||||
}
|
||||
}
|
||||
if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any))
|
||||
{
|
||||
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in adapters)
|
||||
{
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses)
|
||||
if (ipep.AddressFamily == unicast.Address.AddressFamily)
|
||||
Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port);
|
||||
}
|
||||
|
||||
/*
|
||||
try {
|
||||
Console.WriteLine( "Listening: {0}:{1}", IPAddress.Loopback, ipep.Port );
|
||||
IPHostEntry iphe = Dns.GetHostEntry( Dns.GetHostName() );
|
||||
IPAddress[] ip = iphe.AddressList;
|
||||
for ( int i = 0; i < ip.Length; ++i )
|
||||
Console.WriteLine( "Listening: {0}:{1}", ip[i], ipep.Port );
|
||||
}
|
||||
catch { }
|
||||
*/
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port);
|
||||
}
|
||||
}
|
||||
|
||||
#if NewAsyncSockets
|
||||
private void Accept_Start()
|
||||
{
|
||||
bool result = false;
|
||||
private void Accept_Start()
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
do {
|
||||
try {
|
||||
result = !m_Listener.AcceptAsync( m_EventArgs );
|
||||
} catch ( SocketException ex ) {
|
||||
NetState.TraceException( ex );
|
||||
break;
|
||||
} catch ( ObjectDisposedException ) {
|
||||
break;
|
||||
}
|
||||
do
|
||||
{
|
||||
try
|
||||
{
|
||||
result = !m_Listener.AcceptAsync(m_EventArgs);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
break;
|
||||
}
|
||||
catch (ObjectDisposedException)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
if ( result )
|
||||
Accept_Process( m_EventArgs );
|
||||
} while ( result );
|
||||
}
|
||||
if (result)
|
||||
Accept_Process(m_EventArgs);
|
||||
} while (result);
|
||||
}
|
||||
|
||||
private void Accept_Completion( object sender, SocketAsyncEventArgs e )
|
||||
{
|
||||
Accept_Process( e );
|
||||
private void Accept_Completion(object sender, SocketAsyncEventArgs e)
|
||||
{
|
||||
Accept_Process(e);
|
||||
|
||||
Accept_Start();
|
||||
}
|
||||
Accept_Start();
|
||||
}
|
||||
|
||||
private void Accept_Process( SocketAsyncEventArgs e )
|
||||
{
|
||||
if ( e.SocketError == SocketError.Success && VerifySocket( e.AcceptSocket ) ) {
|
||||
Enqueue( e.AcceptSocket );
|
||||
} else {
|
||||
Release( e.AcceptSocket );
|
||||
}
|
||||
private void Accept_Process(SocketAsyncEventArgs e)
|
||||
{
|
||||
if (e.SocketError == SocketError.Success && VerifySocket(e.AcceptSocket))
|
||||
Enqueue(e.AcceptSocket);
|
||||
else
|
||||
Release(e.AcceptSocket);
|
||||
|
||||
e.AcceptSocket = null;
|
||||
}
|
||||
e.AcceptSocket = null;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
private void OnAccept( IAsyncResult asyncResult ) {
|
||||
Socket listener = (Socket) asyncResult.AsyncState;
|
||||
|
||||
|
|
@ -205,71 +218,85 @@ namespace Server.Network
|
|||
}
|
||||
#endif
|
||||
|
||||
private bool VerifySocket( Socket socket ) {
|
||||
try {
|
||||
SocketConnectEventArgs args = new SocketConnectEventArgs( socket );
|
||||
private bool VerifySocket(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
SocketConnectEventArgs args = new SocketConnectEventArgs(socket);
|
||||
|
||||
EventSink.InvokeSocketConnect( args );
|
||||
EventSink.InvokeSocketConnect(args);
|
||||
|
||||
return args.AllowConnection;
|
||||
} catch ( Exception ex ) {
|
||||
NetState.TraceException( ex );
|
||||
return args.AllowConnection;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private void Enqueue( Socket socket ) {
|
||||
lock ( m_AcceptedSyncRoot ) {
|
||||
m_Accepted.Enqueue( socket );
|
||||
}
|
||||
private void Enqueue(Socket socket)
|
||||
{
|
||||
lock (m_AcceptedSyncRoot)
|
||||
{
|
||||
m_Accepted.Enqueue(socket);
|
||||
}
|
||||
|
||||
Core.Set();
|
||||
}
|
||||
Core.Set();
|
||||
}
|
||||
|
||||
private void Release( Socket socket ) {
|
||||
try {
|
||||
socket.Shutdown( SocketShutdown.Both );
|
||||
} catch ( SocketException ex ) {
|
||||
NetState.TraceException( ex );
|
||||
}
|
||||
private void Release(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
}
|
||||
|
||||
try {
|
||||
socket.Close();
|
||||
} catch ( SocketException ex ) {
|
||||
NetState.TraceException( ex );
|
||||
}
|
||||
}
|
||||
try
|
||||
{
|
||||
socket.Close();
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public Socket[] Slice()
|
||||
{
|
||||
Socket[] array;
|
||||
public Socket[] Slice()
|
||||
{
|
||||
Socket[] array;
|
||||
|
||||
lock ( m_AcceptedSyncRoot )
|
||||
{
|
||||
if ( m_Accepted.Count == 0 )
|
||||
return m_EmptySockets;
|
||||
lock (m_AcceptedSyncRoot)
|
||||
{
|
||||
if (m_Accepted.Count == 0)
|
||||
return m_EmptySockets;
|
||||
|
||||
array = m_Accepted.ToArray();
|
||||
m_Accepted.Clear();
|
||||
}
|
||||
array = m_Accepted.ToArray();
|
||||
m_Accepted.Clear();
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
return array;
|
||||
}
|
||||
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Socket socket = Interlocked.Exchange<Socket>(ref m_Listener, null);
|
||||
public void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing)
|
||||
{
|
||||
Socket socket = Interlocked.Exchange(ref m_Listener, null);
|
||||
|
||||
socket?.Close();
|
||||
}
|
||||
}
|
||||
socket?.Close();
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
Dispose(true);
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -27,241 +27,263 @@ using Server.Diagnostics;
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class MessagePump
|
||||
{
|
||||
private Queue<NetState> m_Queue;
|
||||
private Queue<NetState> m_WorkingQueue;
|
||||
private Queue<NetState> m_Throttled;
|
||||
public class MessagePump
|
||||
{
|
||||
private const int BufferSize = 4096;
|
||||
private BufferPool m_Buffers = new BufferPool("Processor", 4, BufferSize);
|
||||
private Queue<NetState> m_Queue;
|
||||
private Queue<NetState> m_Throttled;
|
||||
private Queue<NetState> m_WorkingQueue;
|
||||
|
||||
public MessagePump()
|
||||
{
|
||||
IPEndPoint[] ipep = Listener.EndPoints;
|
||||
public MessagePump()
|
||||
{
|
||||
IPEndPoint[] ipep = Listener.EndPoints;
|
||||
|
||||
Listeners = new Listener[ipep.Length];
|
||||
Listeners = new Listener[ipep.Length];
|
||||
|
||||
bool success = false;
|
||||
bool success = false;
|
||||
|
||||
do {
|
||||
for ( int i = 0; i < ipep.Length; i++ ) {
|
||||
Listener l = new Listener( ipep[i] );
|
||||
if ( !success && l != null )
|
||||
success = true;
|
||||
Listeners[i] = l;
|
||||
}
|
||||
do
|
||||
{
|
||||
for (int i = 0; i < ipep.Length; i++)
|
||||
{
|
||||
Listener l = new Listener(ipep[i]);
|
||||
if (!success)
|
||||
success = true;
|
||||
Listeners[i] = l;
|
||||
}
|
||||
|
||||
if ( !success ) {
|
||||
Console.WriteLine( "Retrying..." );
|
||||
Thread.Sleep( 10000 );
|
||||
}
|
||||
} while ( !success );
|
||||
if (!success)
|
||||
{
|
||||
Console.WriteLine("Retrying...");
|
||||
Thread.Sleep(10000);
|
||||
}
|
||||
} while (!success);
|
||||
|
||||
m_Queue = new Queue<NetState>();
|
||||
m_WorkingQueue = new Queue<NetState>();
|
||||
m_Throttled = new Queue<NetState>();
|
||||
}
|
||||
m_Queue = new Queue<NetState>();
|
||||
m_WorkingQueue = new Queue<NetState>();
|
||||
m_Throttled = new Queue<NetState>();
|
||||
}
|
||||
|
||||
public Listener[] Listeners { get; set; }
|
||||
public Listener[] Listeners{ get; set; }
|
||||
|
||||
public void AddListener( Listener l )
|
||||
{
|
||||
Listener[] old = Listeners;
|
||||
public void AddListener(Listener l)
|
||||
{
|
||||
Listener[] old = Listeners;
|
||||
|
||||
Listeners = new Listener[old.Length + 1];
|
||||
Listeners = new Listener[old.Length + 1];
|
||||
|
||||
for ( int i = 0; i < old.Length; ++i )
|
||||
Listeners[i] = old[i];
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
Listeners[i] = old[i];
|
||||
|
||||
Listeners[old.Length] = l;
|
||||
}
|
||||
Listeners[old.Length] = l;
|
||||
}
|
||||
|
||||
private void CheckListener()
|
||||
{
|
||||
for ( int j = 0; j < Listeners.Length; ++j )
|
||||
{
|
||||
Socket[] accepted = Listeners[j].Slice();
|
||||
private void CheckListener()
|
||||
{
|
||||
for (int j = 0; j < Listeners.Length; ++j)
|
||||
{
|
||||
Socket[] accepted = Listeners[j].Slice();
|
||||
|
||||
for ( int i = 0; i < accepted.Length; ++i )
|
||||
{
|
||||
NetState ns = new NetState( accepted[i], this );
|
||||
ns.Start();
|
||||
for (int i = 0; i < accepted.Length; ++i)
|
||||
{
|
||||
NetState ns = new NetState(accepted[i], this);
|
||||
ns.Start();
|
||||
|
||||
if ( ns.Running )
|
||||
Console.WriteLine( "Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count );
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ns.Running)
|
||||
Console.WriteLine("Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void OnReceive( NetState ns )
|
||||
{
|
||||
lock ( this )
|
||||
m_Queue.Enqueue( ns );
|
||||
public void OnReceive(NetState ns)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
m_Queue.Enqueue(ns);
|
||||
}
|
||||
|
||||
Core.Set();
|
||||
}
|
||||
Core.Set();
|
||||
}
|
||||
|
||||
public void Slice()
|
||||
{
|
||||
CheckListener();
|
||||
public void Slice()
|
||||
{
|
||||
CheckListener();
|
||||
|
||||
lock ( this )
|
||||
{
|
||||
Queue<NetState> temp = m_WorkingQueue;
|
||||
m_WorkingQueue = m_Queue;
|
||||
m_Queue = temp;
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
Queue<NetState> temp = m_WorkingQueue;
|
||||
m_WorkingQueue = m_Queue;
|
||||
m_Queue = temp;
|
||||
}
|
||||
|
||||
while ( m_WorkingQueue.Count > 0 )
|
||||
{
|
||||
NetState ns = m_WorkingQueue.Dequeue();
|
||||
while (m_WorkingQueue.Count > 0)
|
||||
{
|
||||
NetState ns = m_WorkingQueue.Dequeue();
|
||||
|
||||
if ( ns.Running )
|
||||
HandleReceive( ns );
|
||||
}
|
||||
if (ns.Running)
|
||||
HandleReceive(ns);
|
||||
}
|
||||
|
||||
lock ( this )
|
||||
{
|
||||
while ( m_Throttled.Count > 0 )
|
||||
m_Queue.Enqueue( m_Throttled.Dequeue() );
|
||||
}
|
||||
}
|
||||
lock (this)
|
||||
{
|
||||
while (m_Throttled.Count > 0)
|
||||
m_Queue.Enqueue(m_Throttled.Dequeue());
|
||||
}
|
||||
}
|
||||
|
||||
private const int BufferSize = 4096;
|
||||
private BufferPool m_Buffers = new BufferPool( "Processor", 4, BufferSize );
|
||||
private bool HandleSeed(NetState ns, ByteQueue buffer)
|
||||
{
|
||||
if (buffer.GetPacketID() == 0xEF)
|
||||
{
|
||||
// new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet
|
||||
// 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients.
|
||||
ns.Seeded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool HandleSeed(NetState ns, ByteQueue buffer) {
|
||||
if (buffer.GetPacketID() == 0xEF) {
|
||||
// new packet in client 6.0.5.0 replaces the traditional seed method with a seed packet
|
||||
// 0xEF = 239 = multicast IP, so this should never appear in a normal seed. So this is backwards compatible with older clients.
|
||||
ns.Seeded = true;
|
||||
return true;
|
||||
}
|
||||
if (buffer.Length >= 4)
|
||||
{
|
||||
byte[] m_Peek = new byte[4];
|
||||
|
||||
if (buffer.Length >= 4) {
|
||||
byte[] m_Peek = new byte[4];
|
||||
buffer.Dequeue(m_Peek, 0, 4);
|
||||
|
||||
buffer.Dequeue(m_Peek, 0, 4);
|
||||
int seed = (m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3];
|
||||
|
||||
int seed = (m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3];
|
||||
if (seed == 0)
|
||||
{
|
||||
Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", ns);
|
||||
ns.Dispose();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (seed == 0) {
|
||||
Console.WriteLine("Login: {0}: Invalid client detected, disconnecting", ns);
|
||||
ns.Dispose();
|
||||
return false;
|
||||
}
|
||||
ns.m_Seed = seed;
|
||||
ns.Seeded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
ns.m_Seed = seed;
|
||||
ns.Seeded = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool CheckEncrypted(NetState ns, int packetID) {
|
||||
if (!ns.SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 && packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF) {
|
||||
Console.WriteLine("Client: {0}: Encrypted client detected, disconnecting", ns);
|
||||
ns.Dispose();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private bool CheckEncrypted(NetState ns, int packetID)
|
||||
{
|
||||
if (!ns.SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 &&
|
||||
packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF)
|
||||
{
|
||||
Console.WriteLine("Client: {0}: Encrypted client detected, disconnecting", ns);
|
||||
ns.Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void HandleReceive( NetState ns )
|
||||
{
|
||||
ByteQueue buffer = ns.Buffer;
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( buffer == null || buffer.Length <= 0 )
|
||||
return;
|
||||
public void HandleReceive(NetState ns)
|
||||
{
|
||||
ByteQueue buffer = ns.Buffer;
|
||||
|
||||
lock ( buffer )
|
||||
{
|
||||
if ( !ns.Seeded ) {
|
||||
if (!HandleSeed(ns, buffer))
|
||||
return;
|
||||
}
|
||||
if (buffer == null || buffer.Length <= 0)
|
||||
return;
|
||||
|
||||
int length = buffer.Length;
|
||||
lock (buffer)
|
||||
{
|
||||
if (!ns.Seeded)
|
||||
if (!HandleSeed(ns, buffer))
|
||||
return;
|
||||
|
||||
while ( length > 0 && ns.Running ) {
|
||||
int packetID = buffer.GetPacketID();
|
||||
int length = buffer.Length;
|
||||
|
||||
if (CheckEncrypted(ns, packetID))
|
||||
break;
|
||||
while (length > 0 && ns.Running)
|
||||
{
|
||||
int packetID = buffer.GetPacketID();
|
||||
|
||||
PacketHandler handler = ns.GetHandler( packetID );
|
||||
if (CheckEncrypted(ns, packetID))
|
||||
break;
|
||||
|
||||
if ( handler == null ) {
|
||||
byte[] data = new byte[length];
|
||||
length = buffer.Dequeue( data, 0, length );
|
||||
new PacketReader( data, length, false ).Trace( ns );
|
||||
break;
|
||||
}
|
||||
PacketHandler handler = ns.GetHandler(packetID);
|
||||
|
||||
int packetLength = handler.Length;
|
||||
if (handler == null)
|
||||
{
|
||||
byte[] data = new byte[length];
|
||||
length = buffer.Dequeue(data, 0, length);
|
||||
new PacketReader(data, length, false).Trace(ns);
|
||||
break;
|
||||
}
|
||||
|
||||
if ( packetLength <= 0 ) {
|
||||
if ( length >= 3 ) {
|
||||
packetLength = buffer.GetPacketLength();
|
||||
int packetLength = handler.Length;
|
||||
|
||||
if ( packetLength < 3 ) {
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (packetLength <= 0)
|
||||
{
|
||||
if (length >= 3)
|
||||
{
|
||||
packetLength = buffer.GetPacketLength();
|
||||
|
||||
if ( length >= packetLength ) {
|
||||
if (handler.Ingame)
|
||||
{
|
||||
if (ns.Mobile == null ) {
|
||||
Console.WriteLine( "Client: {0}: Sent ingame packet (0x{1:X2}) before having been attached to a mobile", ns, packetID );
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
if (packetLength < 3)
|
||||
{
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ns.Mobile.Deleted) {
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (length >= packetLength)
|
||||
{
|
||||
if (handler.Ingame)
|
||||
{
|
||||
if (ns.Mobile == null)
|
||||
{
|
||||
Console.WriteLine(
|
||||
"Client: {0}: Sent ingame packet (0x{1:X2}) before having been attached to a mobile", ns,
|
||||
packetID);
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
|
||||
ThrottlePacketCallback throttler = handler.ThrottleCallback;
|
||||
if (ns.Mobile.Deleted)
|
||||
{
|
||||
ns.Dispose();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( throttler != null && !throttler( ns ) ) {
|
||||
m_Throttled.Enqueue( ns );
|
||||
return;
|
||||
}
|
||||
ThrottlePacketCallback throttler = handler.ThrottleCallback;
|
||||
|
||||
PacketReceiveProfile prof = null;
|
||||
if (throttler != null && !throttler(ns))
|
||||
{
|
||||
m_Throttled.Enqueue(ns);
|
||||
return;
|
||||
}
|
||||
|
||||
if (Core.Profiling) prof = PacketReceiveProfile.Acquire( packetID );
|
||||
PacketReceiveProfile prof = null;
|
||||
|
||||
prof?.Start();
|
||||
if (Core.Profiling) prof = PacketReceiveProfile.Acquire(packetID);
|
||||
|
||||
byte[] packetBuffer;
|
||||
prof?.Start();
|
||||
|
||||
if ( BufferSize >= packetLength )
|
||||
packetBuffer = m_Buffers.AcquireBuffer();
|
||||
else
|
||||
packetBuffer = new byte[packetLength];
|
||||
byte[] packetBuffer = BufferSize >= packetLength ? m_Buffers.AcquireBuffer() : new byte[packetLength];
|
||||
|
||||
packetLength = buffer.Dequeue( packetBuffer, 0, packetLength );
|
||||
packetLength = buffer.Dequeue(packetBuffer, 0, packetLength);
|
||||
|
||||
PacketReader r = new PacketReader( packetBuffer, packetLength, handler.Length != 0 );
|
||||
PacketReader r = new PacketReader(packetBuffer, packetLength, handler.Length != 0);
|
||||
|
||||
handler.OnReceive( ns, r );
|
||||
length = buffer.Length;
|
||||
handler.OnReceive(ns, r);
|
||||
length = buffer.Length;
|
||||
|
||||
if ( BufferSize >= packetLength )
|
||||
m_Buffers.ReleaseBuffer( packetBuffer );
|
||||
if (BufferSize >= packetLength)
|
||||
m_Buffers.ReleaseBuffer(packetBuffer);
|
||||
|
||||
prof?.Finish( packetLength );
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
prof?.Finish(packetLength);
|
||||
}
|
||||
else
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,27 +20,28 @@
|
|||
|
||||
namespace Server.Network
|
||||
{
|
||||
public delegate void OnPacketReceive( NetState state, PacketReader pvSrc );
|
||||
public delegate bool ThrottlePacketCallback( NetState state );
|
||||
public delegate void OnPacketReceive(NetState state, PacketReader pvSrc);
|
||||
|
||||
public class PacketHandler
|
||||
{
|
||||
public PacketHandler( int packetID, int length, bool ingame, OnPacketReceive onReceive )
|
||||
{
|
||||
PacketID = packetID;
|
||||
Length = length;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
public delegate bool ThrottlePacketCallback(NetState state);
|
||||
|
||||
public int PacketID { get; }
|
||||
public class PacketHandler
|
||||
{
|
||||
public PacketHandler(int packetID, int length, bool ingame, OnPacketReceive onReceive)
|
||||
{
|
||||
PacketID = packetID;
|
||||
Length = length;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int Length { get; }
|
||||
public int PacketID{ get; }
|
||||
|
||||
public OnPacketReceive OnReceive { get; }
|
||||
public int Length{ get; }
|
||||
|
||||
public ThrottlePacketCallback ThrottleCallback { get; set; }
|
||||
public OnPacketReceive OnReceive{ get; }
|
||||
|
||||
public bool Ingame { get; }
|
||||
}
|
||||
public ThrottlePacketCallback ThrottleCallback{ get; set; }
|
||||
|
||||
public bool Ingame{ get; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -18,426 +18,420 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Text;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class PacketReader
|
||||
{
|
||||
private int m_Index;
|
||||
|
||||
public PacketReader( byte[] data, int size, bool fixedSize )
|
||||
{
|
||||
Buffer = data;
|
||||
Size = size;
|
||||
m_Index = fixedSize ? 1 : 3;
|
||||
}
|
||||
|
||||
public byte[] Buffer { get; }
|
||||
|
||||
public int Size { get; }
|
||||
|
||||
public void Trace( NetState state )
|
||||
{
|
||||
try
|
||||
{
|
||||
using ( StreamWriter sw = new StreamWriter( "Packets.log", true ) )
|
||||
{
|
||||
byte[] buffer = Buffer;
|
||||
|
||||
if ( buffer.Length > 0 )
|
||||
sw.WriteLine( "Client: {0}: Unhandled packet 0x{1:X2}", state, buffer[0] );
|
||||
|
||||
using ( MemoryStream ms = new MemoryStream( buffer ) )
|
||||
Utility.FormatBuffer( sw, ms, buffer.Length );
|
||||
|
||||
sw.WriteLine();
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public int Seek( int offset, SeekOrigin origin )
|
||||
{
|
||||
switch ( origin )
|
||||
{
|
||||
case SeekOrigin.Begin: m_Index = offset; break;
|
||||
case SeekOrigin.Current: m_Index += offset; break;
|
||||
case SeekOrigin.End: m_Index = Size - offset; break;
|
||||
}
|
||||
|
||||
return m_Index;
|
||||
}
|
||||
public class PacketReader
|
||||
{
|
||||
private int m_Index;
|
||||
|
||||
public PacketReader(byte[] data, int size, bool fixedSize)
|
||||
{
|
||||
Buffer = data;
|
||||
Size = size;
|
||||
m_Index = fixedSize ? 1 : 3;
|
||||
}
|
||||
|
||||
public byte[] Buffer{ get; }
|
||||
|
||||
public int Size{ get; }
|
||||
|
||||
public void Trace(NetState state)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter("Packets.log", true))
|
||||
{
|
||||
byte[] buffer = Buffer;
|
||||
|
||||
if (buffer.Length > 0)
|
||||
sw.WriteLine("Client: {0}: Unhandled packet 0x{1:X2}", state, buffer[0]);
|
||||
|
||||
using (MemoryStream ms = new MemoryStream(buffer))
|
||||
{
|
||||
Utility.FormatBuffer(sw, ms, buffer.Length);
|
||||
}
|
||||
|
||||
sw.WriteLine();
|
||||
sw.WriteLine();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public int Seek(int offset, SeekOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
m_Index = offset;
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
m_Index += offset;
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
m_Index = Size - offset;
|
||||
break;
|
||||
}
|
||||
|
||||
return m_Index;
|
||||
}
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
if (m_Index + 4 > Size)
|
||||
return 0;
|
||||
|
||||
return (Buffer[m_Index++] << 24)
|
||||
| (Buffer[m_Index++] << 16)
|
||||
| (Buffer[m_Index++] << 8)
|
||||
| Buffer[m_Index++];
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
if (m_Index + 2 > Size)
|
||||
return 0;
|
||||
|
||||
return (short)((Buffer[m_Index++] << 8) | Buffer[m_Index++]);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
if (m_Index + 1 > Size)
|
||||
return 0;
|
||||
|
||||
return Buffer[m_Index++];
|
||||
}
|
||||
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
if (m_Index + 4 > Size)
|
||||
return 0;
|
||||
|
||||
public int ReadInt32()
|
||||
{
|
||||
if ( (m_Index + 4) > Size )
|
||||
return 0;
|
||||
|
||||
return (Buffer[m_Index++] << 24)
|
||||
| (Buffer[m_Index++] << 16)
|
||||
| (Buffer[m_Index++] << 8)
|
||||
| Buffer[m_Index++];
|
||||
}
|
||||
|
||||
public short ReadInt16()
|
||||
{
|
||||
if ( (m_Index + 2) > Size )
|
||||
return 0;
|
||||
return (uint)((Buffer[m_Index++] << 24) | (Buffer[m_Index++] << 16) | (Buffer[m_Index++] << 8) |
|
||||
Buffer[m_Index++]);
|
||||
}
|
||||
|
||||
return (short)((Buffer[m_Index++] << 8) | Buffer[m_Index++]);
|
||||
}
|
||||
|
||||
public byte ReadByte()
|
||||
{
|
||||
if ( (m_Index + 1) > Size )
|
||||
return 0;
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
if (m_Index + 2 > Size)
|
||||
return 0;
|
||||
|
||||
return (ushort)((Buffer[m_Index++] << 8) | Buffer[m_Index++]);
|
||||
}
|
||||
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
if (m_Index + 1 > Size)
|
||||
return 0;
|
||||
|
||||
return (sbyte)Buffer[m_Index++];
|
||||
}
|
||||
|
||||
return Buffer[m_Index++];
|
||||
}
|
||||
|
||||
public uint ReadUInt32()
|
||||
{
|
||||
if ( (m_Index + 4) > Size )
|
||||
return 0;
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
if (m_Index + 1 > Size)
|
||||
return false;
|
||||
|
||||
return (uint)((Buffer[m_Index++] << 24) | (Buffer[m_Index++] << 16) | (Buffer[m_Index++] << 8) | Buffer[m_Index++]);
|
||||
}
|
||||
return Buffer[m_Index++] != 0;
|
||||
}
|
||||
|
||||
public ushort ReadUInt16()
|
||||
{
|
||||
if ( (m_Index + 2) > Size )
|
||||
return 0;
|
||||
public string ReadUnicodeStringLE()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return (ushort)((Buffer[m_Index++] << 8) | Buffer[m_Index++]);
|
||||
}
|
||||
int c;
|
||||
|
||||
public sbyte ReadSByte()
|
||||
{
|
||||
if ( (m_Index + 1) > Size )
|
||||
return 0;
|
||||
|
||||
return (sbyte)Buffer[m_Index++];
|
||||
}
|
||||
|
||||
public bool ReadBoolean()
|
||||
{
|
||||
if ( (m_Index + 1) > Size )
|
||||
return false;
|
||||
while (m_Index + 1 < Size && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return ( Buffer[m_Index++] != 0 );
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLE()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public string ReadUnicodeStringLESafe(int fixedLength)
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
int c;
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
while ( (m_Index + 1) < Size && (c = (Buffer[m_Index++] | (Buffer[m_Index++] << 8))) != 0 )
|
||||
sb.Append( (char)c );
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
int c;
|
||||
|
||||
public string ReadUnicodeStringLESafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
while (m_Index + 1 < bound && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
m_Index = end;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
int c;
|
||||
public string ReadUnicodeStringLESafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = (Buffer[m_Index++] | (Buffer[m_Index++] << 8))) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
int c;
|
||||
|
||||
m_Index = end;
|
||||
while (m_Index + 1 < Size && (c = Buffer[m_Index++] | (Buffer[m_Index++] << 8)) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLESafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < Size && (c = (Buffer[m_Index++] | (Buffer[m_Index++] << 8))) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
while (m_Index + 1 < Size && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
int c;
|
||||
|
||||
while ( (m_Index + 1) < Size && (c = ((Buffer[m_Index++] << 8) | Buffer[m_Index++])) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
while (m_Index + 1 < Size && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public bool IsSafeChar(int c)
|
||||
{
|
||||
return c >= 0x20 && c < 0xFFFE;
|
||||
}
|
||||
|
||||
int c;
|
||||
public string ReadUTF8StringSafe(int fixedLength)
|
||||
{
|
||||
if (m_Index >= Size)
|
||||
{
|
||||
m_Index += fixedLength;
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
while ( (m_Index + 1) < Size && (c = ((Buffer[m_Index++] << 8) | Buffer[m_Index++])) != 0 )
|
||||
sb.Append( (char)c );
|
||||
int bound = m_Index + fixedLength;
|
||||
//int end = bound;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
public bool IsSafeChar( int c )
|
||||
{
|
||||
return ( c >= 0x20 && c < 0xFFFE );
|
||||
}
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
int start = m_Index;
|
||||
|
||||
public string ReadUTF8StringSafe( int fixedLength )
|
||||
{
|
||||
if ( m_Index >= Size )
|
||||
{
|
||||
m_Index += fixedLength;
|
||||
return string.Empty;
|
||||
}
|
||||
while (index < bound && Buffer[index++] != 0)
|
||||
++count;
|
||||
|
||||
int bound = m_Index + fixedLength;
|
||||
//int end = bound;
|
||||
index = 0;
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
int start = m_Index;
|
||||
while (m_Index < bound && (value = Buffer[m_Index++]) != 0)
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
while ( index < bound && Buffer[index++] != 0 )
|
||||
++count;
|
||||
string s = Utility.UTF8.GetString(buffer);
|
||||
|
||||
index = 0;
|
||||
bool isSafe = true;
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
for (int i = 0; isSafe && i < s.Length; ++i)
|
||||
isSafe = IsSafeChar(s[i]);
|
||||
|
||||
while ( m_Index < bound && (value = Buffer[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
m_Index = start + fixedLength;
|
||||
|
||||
string s = Utility.UTF8.GetString( buffer );
|
||||
if (isSafe)
|
||||
return s;
|
||||
|
||||
bool isSafe = true;
|
||||
StringBuilder sb = new StringBuilder(s.Length);
|
||||
|
||||
for ( int i = 0; isSafe && i < s.Length; ++i )
|
||||
isSafe = IsSafeChar( (int) s[i] );
|
||||
for (int i = 0; i < s.Length; ++i)
|
||||
if (IsSafeChar(s[i]))
|
||||
sb.Append(s[i]);
|
||||
|
||||
m_Index = start + fixedLength;
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
if ( isSafe )
|
||||
return s;
|
||||
public string ReadUTF8StringSafe()
|
||||
{
|
||||
if (m_Index >= Size)
|
||||
return string.Empty;
|
||||
|
||||
StringBuilder sb = new StringBuilder( s.Length );
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
|
||||
for ( int i = 0; i < s.Length; ++i )
|
||||
if ( IsSafeChar( (int) s[i] ) )
|
||||
sb.Append( s[i] );
|
||||
while (index < Size && Buffer[index++] != 0)
|
||||
++count;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
index = 0;
|
||||
|
||||
public string ReadUTF8StringSafe()
|
||||
{
|
||||
if ( m_Index >= Size )
|
||||
return string.Empty;
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
while (m_Index < Size && (value = Buffer[m_Index++]) != 0)
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
while ( index < Size && Buffer[index++] != 0 )
|
||||
++count;
|
||||
string s = Utility.UTF8.GetString(buffer);
|
||||
|
||||
index = 0;
|
||||
bool isSafe = true;
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
for (int i = 0; isSafe && i < s.Length; ++i)
|
||||
isSafe = IsSafeChar(s[i]);
|
||||
|
||||
while ( m_Index < Size && (value = Buffer[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
if (isSafe)
|
||||
return s;
|
||||
|
||||
string s = Utility.UTF8.GetString( buffer );
|
||||
StringBuilder sb = new StringBuilder(s.Length);
|
||||
|
||||
bool isSafe = true;
|
||||
for (int i = 0; i < s.Length; ++i)
|
||||
if (IsSafeChar(s[i]))
|
||||
sb.Append(s[i]);
|
||||
|
||||
for ( int i = 0; isSafe && i < s.Length; ++i )
|
||||
isSafe = IsSafeChar( (int) s[i] );
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
if ( isSafe )
|
||||
return s;
|
||||
public string ReadUTF8String()
|
||||
{
|
||||
if (m_Index >= Size)
|
||||
return string.Empty;
|
||||
|
||||
StringBuilder sb = new StringBuilder( s.Length );
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
|
||||
for ( int i = 0; i < s.Length; ++i )
|
||||
{
|
||||
if ( IsSafeChar( (int) s[i] ) )
|
||||
sb.Append( s[i] );
|
||||
}
|
||||
while (index < Size && Buffer[index++] != 0)
|
||||
++count;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
index = 0;
|
||||
|
||||
public string ReadUTF8String()
|
||||
{
|
||||
if ( m_Index >= Size )
|
||||
return string.Empty;
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
|
||||
int count = 0;
|
||||
int index = m_Index;
|
||||
while (m_Index < Size && (value = Buffer[m_Index++]) != 0)
|
||||
buffer[index++] = (byte)value;
|
||||
|
||||
while ( index < Size && Buffer[index++] != 0 )
|
||||
++count;
|
||||
return Utility.UTF8.GetString(buffer);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
byte[] buffer = new byte[count];
|
||||
int value = 0;
|
||||
int c;
|
||||
|
||||
while ( m_Index < Size && (value = Buffer[m_Index++]) != 0 )
|
||||
buffer[index++] = (byte)value;
|
||||
while (m_Index < Size && (c = Buffer[m_Index++]) != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return Utility.UTF8.GetString( buffer );
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public string ReadStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
int c;
|
||||
|
||||
while ( m_Index < Size && (c = Buffer[m_Index++]) != 0 )
|
||||
sb.Append( (char)c );
|
||||
while (m_Index < Size && (c = Buffer[m_Index++]) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
public string ReadUnicodeStringSafe(int fixedLength)
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
int c;
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
while ( m_Index < Size && (c = Buffer[m_Index++]) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
int c;
|
||||
|
||||
public string ReadUnicodeStringSafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
while (m_Index + 1 < bound && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
m_Index = end;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
int c;
|
||||
public string ReadUnicodeString(int fixedLength)
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = ((Buffer[m_Index++] << 8) | Buffer[m_Index++])) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
m_Index = end;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
int c;
|
||||
|
||||
public string ReadUnicodeString( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + (fixedLength << 1);
|
||||
int end = bound;
|
||||
while (m_Index + 1 < bound && (c = (Buffer[m_Index++] << 8) | Buffer[m_Index++]) != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
m_Index = end;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
int c;
|
||||
public string ReadStringSafe(int fixedLength)
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
|
||||
while ( (m_Index + 1) < bound && (c = ((Buffer[m_Index++] << 8) | Buffer[m_Index++])) != 0 )
|
||||
sb.Append( (char)c );
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
m_Index = end;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
int c;
|
||||
|
||||
public string ReadStringSafe( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
while (m_Index < bound && (c = Buffer[m_Index++]) != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
m_Index = end;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
int c;
|
||||
public string ReadString(int fixedLength)
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
|
||||
while ( m_Index < bound && (c = Buffer[m_Index++]) != 0 )
|
||||
{
|
||||
if ( IsSafeChar( c ) )
|
||||
sb.Append( (char)c );
|
||||
}
|
||||
if (bound > Size)
|
||||
bound = Size;
|
||||
|
||||
m_Index = end;
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
int c;
|
||||
|
||||
public string ReadString( int fixedLength )
|
||||
{
|
||||
int bound = m_Index + fixedLength;
|
||||
int end = bound;
|
||||
while (m_Index < bound && (c = Buffer[m_Index++]) != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if ( bound > Size )
|
||||
bound = Size;
|
||||
m_Index = end;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
int c;
|
||||
|
||||
while ( m_Index < bound && (c = Buffer[m_Index++]) != 0 )
|
||||
sb.Append( (char)c );
|
||||
|
||||
m_Index = end;
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -19,433 +19,441 @@
|
|||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static Stack<PacketWriter> m_Pool = new Stack<PacketWriter>();
|
||||
|
||||
public static PacketWriter CreateInstance()
|
||||
{
|
||||
return CreateInstance( 32 );
|
||||
}
|
||||
|
||||
public static PacketWriter CreateInstance( int capacity )
|
||||
{
|
||||
PacketWriter pw = null;
|
||||
|
||||
lock ( m_Pool )
|
||||
{
|
||||
if ( m_Pool.Count > 0 )
|
||||
{
|
||||
pw = m_Pool.Pop();
|
||||
|
||||
if ( pw != null )
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.m_Stream.SetLength( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( pw == null )
|
||||
pw = new PacketWriter( capacity );
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
public static void ReleaseInstance( PacketWriter pw )
|
||||
{
|
||||
lock ( m_Pool )
|
||||
{
|
||||
if ( !m_Pool.Contains( pw ) )
|
||||
{
|
||||
m_Pool.Push( pw );
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
using ( StreamWriter op = new StreamWriter( "neterr.log" ) )
|
||||
{
|
||||
op.WriteLine("{0}\tInstance pool contains writer", DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine( "net error" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Internal stream which holds the entire packet.
|
||||
/// </summary>
|
||||
private MemoryStream m_Stream;
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private byte[] m_Buffer = new byte[4];
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with the default capacity of 4 bytes.
|
||||
/// </summary>
|
||||
public PacketWriter() : this( 32 )
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with a given capacity.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity for the internal stream.</param>
|
||||
public PacketWriter( int capacity )
|
||||
{
|
||||
m_Stream = new MemoryStream( capacity );
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.
|
||||
/// </summary>
|
||||
public void Write( bool value )
|
||||
{
|
||||
m_Stream.WriteByte( (byte)(value ? 1 : 0) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( byte value )
|
||||
{
|
||||
m_Stream.WriteByte( value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( sbyte value )
|
||||
{
|
||||
m_Stream.WriteByte( (byte) value );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( short value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( ushort value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 2 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( int value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 4 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write( uint value )
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte) value;
|
||||
|
||||
m_Stream.Write( m_Buffer, 0, 4 );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the underlying stream
|
||||
/// </summary>
|
||||
public void Write( byte[] buffer, int offset, int size )
|
||||
{
|
||||
m_Stream.Write( buffer, offset, size );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteAsciiFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteAsciiFixed() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + size );
|
||||
|
||||
if ( length >= size )
|
||||
m_Stream.Position += Encoding.ASCII.GetBytes( value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
else
|
||||
{
|
||||
Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteAsciiNull() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + length + 1 );
|
||||
|
||||
Encoding.ASCII.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += length + 1;
|
||||
|
||||
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
m_Stream.WriteByte( 0 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteLittleUniNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteLittleUniNull() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) );
|
||||
|
||||
m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += 2;
|
||||
|
||||
/*byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteLittleUniFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteLittleUniFixed() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + size );
|
||||
|
||||
if ( ( length * 2 ) >= size )
|
||||
m_Stream.Position += Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
else
|
||||
{
|
||||
Encoding.Unicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteBigUniNull( string value )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteBigUniNull() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + ( ( length + 1 ) * 2 ) );
|
||||
|
||||
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += 2;
|
||||
|
||||
/*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteBigUniFixed( string value, int size )
|
||||
{
|
||||
if ( value == null )
|
||||
{
|
||||
Console.WriteLine( "Network: Attempted to WriteBigUniFixed() with null value" );
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength( m_Stream.Length + size );
|
||||
|
||||
if ( ( length * 2 ) >= size )
|
||||
m_Stream.Position += Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
else
|
||||
{
|
||||
Encoding.BigEndianUnicode.GetBytes( value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position );
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill( (int) (m_Capacity - m_Stream.Length) );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill( int length )
|
||||
{
|
||||
if ( m_Stream.Position == m_Stream.Length )
|
||||
{
|
||||
m_Stream.SetLength( m_Stream.Length + length );
|
||||
m_Stream.Seek( 0, SeekOrigin.End );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( new byte[length], 0, length );
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length => m_Stream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get => m_Stream.Position;
|
||||
set => m_Stream.Position = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream => m_Stream;
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek( long offset, SeekOrigin origin )
|
||||
{
|
||||
return m_Stream.Seek( offset, origin );
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
return m_Stream.ToArray();
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static Stack<PacketWriter> m_Pool = new Stack<PacketWriter>();
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private byte[] m_Buffer = new byte[4];
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <summary>
|
||||
/// Internal stream which holds the entire packet.
|
||||
/// </summary>
|
||||
private MemoryStream m_Stream;
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with the default capacity of 4 bytes.
|
||||
/// </summary>
|
||||
public PacketWriter() : this(32)
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates a new PacketWriter instance with a given capacity.
|
||||
/// </summary>
|
||||
/// <param name="capacity">Initial capacity for the internal stream.</param>
|
||||
public PacketWriter(int capacity)
|
||||
{
|
||||
m_Stream = new MemoryStream(capacity);
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length => m_Stream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get => m_Stream.Position;
|
||||
set => m_Stream.Position = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream => m_Stream;
|
||||
|
||||
public static PacketWriter CreateInstance()
|
||||
{
|
||||
return CreateInstance(32);
|
||||
}
|
||||
|
||||
public static PacketWriter CreateInstance(int capacity)
|
||||
{
|
||||
PacketWriter pw = null;
|
||||
|
||||
lock (m_Pool)
|
||||
{
|
||||
if (m_Pool.Count > 0)
|
||||
{
|
||||
pw = m_Pool.Pop();
|
||||
|
||||
if (pw != null)
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.m_Stream.SetLength(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pw == null)
|
||||
pw = new PacketWriter(capacity);
|
||||
|
||||
return pw;
|
||||
}
|
||||
|
||||
public static void ReleaseInstance(PacketWriter pw)
|
||||
{
|
||||
lock (m_Pool)
|
||||
{
|
||||
if (!m_Pool.Contains(pw))
|
||||
m_Pool.Push(pw);
|
||||
else
|
||||
try
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("neterr.log"))
|
||||
{
|
||||
op.WriteLine("{0}\tInstance pool contains writer", DateTime.UtcNow);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("net error");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte boolean value to the underlying stream. False is represented by 0, true by 1.
|
||||
/// </summary>
|
||||
public void Write(bool value)
|
||||
{
|
||||
m_Stream.WriteByte((byte)(value ? 1 : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
m_Stream.WriteByte(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
m_Stream.WriteByte((byte)value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(short value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte)value;
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 2-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(ushort value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 8);
|
||||
m_Buffer[1] = (byte)value;
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, 2);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(int value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte)value;
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 4-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(uint value)
|
||||
{
|
||||
m_Buffer[0] = (byte)(value >> 24);
|
||||
m_Buffer[1] = (byte)(value >> 16);
|
||||
m_Buffer[2] = (byte)(value >> 8);
|
||||
m_Buffer[3] = (byte)value;
|
||||
|
||||
m_Stream.Write(m_Buffer, 0, 4);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a sequence of bytes to the underlying stream
|
||||
/// </summary>
|
||||
public void Write(byte[] buffer, int offset, int size)
|
||||
{
|
||||
m_Stream.Write(buffer, offset, size);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length ASCII-encoded string value to the underlying stream. To fit (size), the string content is either
|
||||
/// truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteAsciiFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteAsciiFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + size);
|
||||
|
||||
if (length >= size)
|
||||
{
|
||||
m_Stream.Position += Encoding.ASCII.GetBytes(value, 0, size, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length ASCII-encoded string value to the underlying stream, followed by a 1-byte null character.
|
||||
/// </summary>
|
||||
public void WriteAsciiNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteAsciiNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + length + 1);
|
||||
|
||||
Encoding.ASCII.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += length + 1;
|
||||
|
||||
/*byte[] buffer = Encoding.ASCII.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
m_Stream.WriteByte( 0 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length little-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteLittleUniNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteLittleUniNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + (length + 1) * 2);
|
||||
|
||||
m_Stream.Position += Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += 2;
|
||||
|
||||
/*byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length little-endian unicode string value to the underlying stream. To fit (size), the string content is
|
||||
/// either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteLittleUniFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteLittleUniFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
m_Stream.Position +=
|
||||
Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.Unicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.Unicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a dynamic-length big-endian unicode string value to the underlying stream, followed by a 2-byte null character.
|
||||
/// </summary>
|
||||
public void WriteBigUniNull(string value)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteBigUniNull() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + (length + 1) * 2);
|
||||
|
||||
m_Stream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += 2;
|
||||
|
||||
/*byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
|
||||
m_Buffer[0] = 0;
|
||||
m_Buffer[1] = 0;
|
||||
m_Stream.Write( m_Buffer, 0, 2 );*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a fixed-length big-endian unicode string value to the underlying stream. To fit (size), the string content is
|
||||
/// either truncated or padded with null characters.
|
||||
/// </summary>
|
||||
public void WriteBigUniFixed(string value, int size)
|
||||
{
|
||||
if (value == null)
|
||||
{
|
||||
Console.WriteLine("Network: Attempted to WriteBigUniFixed() with null value");
|
||||
value = string.Empty;
|
||||
}
|
||||
|
||||
size *= 2;
|
||||
|
||||
int length = value.Length;
|
||||
|
||||
m_Stream.SetLength(m_Stream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
m_Stream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, m_Stream.GetBuffer(), (int)m_Stream.Position);
|
||||
m_Stream.Position += size;
|
||||
}
|
||||
|
||||
/*size *= 2;
|
||||
|
||||
byte[] buffer = Encoding.BigEndianUnicode.GetBytes( value );
|
||||
|
||||
if ( buffer.Length >= size )
|
||||
{
|
||||
m_Stream.Write( buffer, 0, size );
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write( buffer, 0, buffer.Length );
|
||||
Fill( size - buffer.Length );
|
||||
}*/
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill((int)(m_Capacity - m_Stream.Length));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill(int length)
|
||||
{
|
||||
if (m_Stream.Position == m_Stream.Length)
|
||||
{
|
||||
m_Stream.SetLength(m_Stream.Length + length);
|
||||
m_Stream.Seek(0, SeekOrigin.End);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Stream.Write(new byte[length], 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
return m_Stream.Seek(offset, origin);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray()
|
||||
{
|
||||
return m_Stream.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -21,189 +21,205 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Network {
|
||||
public class SendQueue {
|
||||
public class Gram {
|
||||
private static Stack<Gram> _pool = new Stack<Gram>();
|
||||
namespace Server.Network
|
||||
{
|
||||
public class SendQueue
|
||||
{
|
||||
private const int PendingCap = 256 * 1024;
|
||||
|
||||
public static Gram Acquire() {
|
||||
lock ( _pool ) {
|
||||
Gram gram;
|
||||
private static int m_CoalesceBufferSize = 512;
|
||||
private static BufferPool m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize);
|
||||
|
||||
if ( _pool.Count > 0 ) {
|
||||
gram = _pool.Pop();
|
||||
} else {
|
||||
gram = new Gram();
|
||||
}
|
||||
private Gram _buffered;
|
||||
|
||||
gram.Buffer = AcquireBuffer();
|
||||
gram.Length = 0;
|
||||
private Queue<Gram> _pending;
|
||||
|
||||
return gram;
|
||||
}
|
||||
}
|
||||
public SendQueue()
|
||||
{
|
||||
_pending = new Queue<Gram>();
|
||||
}
|
||||
|
||||
public byte[] Buffer { get; private set; }
|
||||
public static int CoalesceBufferSize
|
||||
{
|
||||
get => m_CoalesceBufferSize;
|
||||
set
|
||||
{
|
||||
if (m_CoalesceBufferSize == value)
|
||||
return;
|
||||
|
||||
public int Length { get; private set; }
|
||||
BufferPool old = m_UnusedBuffers;
|
||||
|
||||
public int Available => ( Buffer.Length - Length );
|
||||
lock (old)
|
||||
{
|
||||
m_UnusedBuffers?.Free();
|
||||
|
||||
public bool IsFull => ( Length == Buffer.Length );
|
||||
m_CoalesceBufferSize = value;
|
||||
m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Gram() {
|
||||
}
|
||||
public bool IsFlushReady => _pending.Count == 0 && _buffered != null;
|
||||
|
||||
public int Write( byte[] buffer, int offset, int length ) {
|
||||
int write = Math.Min( length, Available );
|
||||
public bool IsEmpty => _pending.Count == 0 && _buffered == null;
|
||||
|
||||
System.Buffer.BlockCopy( buffer, offset, Buffer, Length, write );
|
||||
public static byte[] AcquireBuffer()
|
||||
{
|
||||
lock (m_UnusedBuffers)
|
||||
{
|
||||
return m_UnusedBuffers.AcquireBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
Length += write;
|
||||
public static void ReleaseBuffer(byte[] buffer)
|
||||
{
|
||||
lock (m_UnusedBuffers)
|
||||
{
|
||||
if (buffer != null && buffer.Length == m_CoalesceBufferSize)
|
||||
m_UnusedBuffers.ReleaseBuffer(buffer);
|
||||
}
|
||||
}
|
||||
|
||||
return write;
|
||||
}
|
||||
public Gram CheckFlushReady()
|
||||
{
|
||||
Gram gram = _buffered;
|
||||
_pending.Enqueue(_buffered);
|
||||
_buffered = null;
|
||||
return gram;
|
||||
}
|
||||
|
||||
public void Release() {
|
||||
lock ( _pool ) {
|
||||
_pool.Push( this );
|
||||
ReleaseBuffer( Buffer );
|
||||
}
|
||||
}
|
||||
}
|
||||
public Gram Dequeue()
|
||||
{
|
||||
Gram gram = null;
|
||||
|
||||
private static int m_CoalesceBufferSize = 512;
|
||||
private static BufferPool m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize );
|
||||
if (_pending.Count > 0)
|
||||
{
|
||||
_pending.Dequeue().Release();
|
||||
|
||||
public static int CoalesceBufferSize {
|
||||
get => m_CoalesceBufferSize;
|
||||
set {
|
||||
if ( m_CoalesceBufferSize == value )
|
||||
return;
|
||||
if (_pending.Count > 0) gram = _pending.Peek();
|
||||
}
|
||||
|
||||
BufferPool old = m_UnusedBuffers;
|
||||
return gram;
|
||||
}
|
||||
|
||||
lock (old) {
|
||||
m_UnusedBuffers?.Free();
|
||||
public Gram Enqueue(byte[] buffer, int length)
|
||||
{
|
||||
return Enqueue(buffer, 0, length);
|
||||
}
|
||||
|
||||
m_CoalesceBufferSize = value;
|
||||
m_UnusedBuffers = new BufferPool( "Coalesced", 2048, m_CoalesceBufferSize );
|
||||
}
|
||||
}
|
||||
}
|
||||
public Gram Enqueue(byte[] buffer, int offset, int length)
|
||||
{
|
||||
if (buffer == null) throw new ArgumentNullException("buffer");
|
||||
|
||||
public static byte[] AcquireBuffer() {
|
||||
lock (m_UnusedBuffers)
|
||||
return m_UnusedBuffers.AcquireBuffer();
|
||||
}
|
||||
if (!(offset >= 0 && offset < buffer.Length))
|
||||
throw new ArgumentOutOfRangeException("offset", offset,
|
||||
"Offset must be greater than or equal to zero and less than the size of the buffer.");
|
||||
if (length < 0 || length > buffer.Length)
|
||||
throw new ArgumentOutOfRangeException("length", length,
|
||||
"Length cannot be less than zero or greater than the size of the buffer.");
|
||||
if (buffer.Length - offset < length)
|
||||
throw new ArgumentException("Offset and length do not point to a valid segment within the buffer.");
|
||||
|
||||
public static void ReleaseBuffer( byte[] buffer ) {
|
||||
lock (m_UnusedBuffers)
|
||||
if ( buffer != null && buffer.Length == m_CoalesceBufferSize )
|
||||
m_UnusedBuffers.ReleaseBuffer( buffer );
|
||||
}
|
||||
int existingBytes = _pending.Count * m_CoalesceBufferSize + (_buffered?.Length ?? 0);
|
||||
|
||||
private Queue<Gram> _pending;
|
||||
if (existingBytes + length > PendingCap) throw new CapacityExceededException();
|
||||
|
||||
private Gram _buffered;
|
||||
Gram gram = null;
|
||||
|
||||
public bool IsFlushReady => ( _pending.Count == 0 && _buffered != null );
|
||||
while (length > 0)
|
||||
{
|
||||
if (_buffered == null) _buffered = Gram.Acquire();
|
||||
|
||||
public bool IsEmpty => ( _pending.Count == 0 && _buffered == null );
|
||||
int bytesWritten = _buffered.Write(buffer, offset, length);
|
||||
|
||||
public SendQueue() {
|
||||
_pending = new Queue<Gram>();
|
||||
}
|
||||
offset += bytesWritten;
|
||||
length -= bytesWritten;
|
||||
|
||||
public Gram CheckFlushReady() {
|
||||
Gram gram = _buffered;
|
||||
_pending.Enqueue(_buffered);
|
||||
_buffered = null;
|
||||
return gram;
|
||||
}
|
||||
if (_buffered.IsFull)
|
||||
{
|
||||
if (_pending.Count == 0) gram = _buffered;
|
||||
|
||||
public Gram Dequeue() {
|
||||
Gram gram = null;
|
||||
_pending.Enqueue(_buffered);
|
||||
_buffered = null;
|
||||
}
|
||||
}
|
||||
|
||||
if ( _pending.Count > 0 ) {
|
||||
_pending.Dequeue().Release();
|
||||
return gram;
|
||||
}
|
||||
|
||||
if ( _pending.Count > 0 ) {
|
||||
gram = _pending.Peek();
|
||||
}
|
||||
}
|
||||
public void Clear()
|
||||
{
|
||||
if (_buffered != null)
|
||||
{
|
||||
_buffered.Release();
|
||||
_buffered = null;
|
||||
}
|
||||
|
||||
return gram;
|
||||
}
|
||||
while (_pending.Count > 0) _pending.Dequeue().Release();
|
||||
}
|
||||
|
||||
private const int PendingCap = 256 * 1024;
|
||||
public class Gram
|
||||
{
|
||||
private static Stack<Gram> _pool = new Stack<Gram>();
|
||||
|
||||
public Gram Enqueue( byte[] buffer, int length ) {
|
||||
return Enqueue( buffer, 0, length );
|
||||
}
|
||||
private Gram()
|
||||
{
|
||||
}
|
||||
|
||||
public Gram Enqueue( byte[] buffer, int offset, int length ) {
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException( "buffer" );
|
||||
}
|
||||
public byte[] Buffer{ get; private set; }
|
||||
|
||||
if ( !(offset >= 0 && offset < buffer.Length) ) {
|
||||
throw new ArgumentOutOfRangeException( "offset", offset, "Offset must be greater than or equal to zero and less than the size of the buffer." );
|
||||
}
|
||||
if ( length < 0 || length > buffer.Length ) {
|
||||
throw new ArgumentOutOfRangeException( "length", length, "Length cannot be less than zero or greater than the size of the buffer." );
|
||||
}
|
||||
if ( ( buffer.Length - offset ) < length ) {
|
||||
throw new ArgumentException( "Offset and length do not point to a valid segment within the buffer." );
|
||||
}
|
||||
public int Length{ get; private set; }
|
||||
|
||||
int existingBytes = ( _pending.Count * m_CoalesceBufferSize ) + (_buffered?.Length ?? 0);
|
||||
public int Available => Buffer.Length - Length;
|
||||
|
||||
if ( ( existingBytes + length ) > PendingCap ) {
|
||||
throw new CapacityExceededException();
|
||||
}
|
||||
public bool IsFull => Length == Buffer.Length;
|
||||
|
||||
Gram gram = null;
|
||||
public static Gram Acquire()
|
||||
{
|
||||
lock (_pool)
|
||||
{
|
||||
Gram gram;
|
||||
|
||||
while ( length > 0 ) {
|
||||
if ( _buffered == null ) { // nothing yet buffered
|
||||
_buffered = Gram.Acquire();
|
||||
}
|
||||
if (_pool.Count > 0)
|
||||
gram = _pool.Pop();
|
||||
else
|
||||
gram = new Gram();
|
||||
|
||||
int bytesWritten = _buffered.Write( buffer, offset, length );
|
||||
gram.Buffer = AcquireBuffer();
|
||||
gram.Length = 0;
|
||||
|
||||
offset += bytesWritten;
|
||||
length -= bytesWritten;
|
||||
return gram;
|
||||
}
|
||||
}
|
||||
|
||||
if ( _buffered.IsFull ) {
|
||||
if ( _pending.Count == 0 ) {
|
||||
gram = _buffered;
|
||||
}
|
||||
public int Write(byte[] buffer, int offset, int length)
|
||||
{
|
||||
int write = Math.Min(length, Available);
|
||||
|
||||
_pending.Enqueue( _buffered );
|
||||
_buffered = null;
|
||||
}
|
||||
}
|
||||
System.Buffer.BlockCopy(buffer, offset, Buffer, Length, write);
|
||||
|
||||
return gram;
|
||||
}
|
||||
Length += write;
|
||||
|
||||
public void Clear() {
|
||||
if ( _buffered != null ) {
|
||||
_buffered.Release();
|
||||
_buffered = null;
|
||||
}
|
||||
return write;
|
||||
}
|
||||
|
||||
while ( _pending.Count > 0 ) {
|
||||
_pending.Dequeue().Release();
|
||||
}
|
||||
}
|
||||
}
|
||||
public void Release()
|
||||
{
|
||||
lock (_pool)
|
||||
{
|
||||
_pool.Push(this);
|
||||
ReleaseBuffer(Buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public sealed class CapacityExceededException : Exception {
|
||||
public CapacityExceededException()
|
||||
: base( "Too much data pending." ) {
|
||||
}
|
||||
}
|
||||
[Serializable]
|
||||
public sealed class CapacityExceededException : Exception
|
||||
{
|
||||
public CapacityExceededException()
|
||||
: base("Too much data pending.")
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,43 +20,43 @@
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public delegate int NotorietyHandler( Mobile source, Mobile target );
|
||||
public delegate int NotorietyHandler(Mobile source, Mobile target);
|
||||
|
||||
public static class Notoriety
|
||||
{
|
||||
public const int Innocent = 1;
|
||||
public const int Ally = 2;
|
||||
public const int CanBeAttacked = 3;
|
||||
public const int Criminal = 4;
|
||||
public const int Enemy = 5;
|
||||
public const int Murderer = 6;
|
||||
public const int Invulnerable = 7;
|
||||
public static class Notoriety
|
||||
{
|
||||
public const int Innocent = 1;
|
||||
public const int Ally = 2;
|
||||
public const int CanBeAttacked = 3;
|
||||
public const int Criminal = 4;
|
||||
public const int Enemy = 5;
|
||||
public const int Murderer = 6;
|
||||
public const int Invulnerable = 7;
|
||||
|
||||
public static NotorietyHandler Handler { get; set; }
|
||||
public static NotorietyHandler Handler{ get; set; }
|
||||
|
||||
public static int[] Hues { get; set; } =
|
||||
{
|
||||
0x000,
|
||||
0x059,
|
||||
0x03F,
|
||||
0x3B2,
|
||||
0x3B2,
|
||||
0x090,
|
||||
0x022,
|
||||
0x035
|
||||
};
|
||||
public static int[] Hues{ get; set; } =
|
||||
{
|
||||
0x000,
|
||||
0x059,
|
||||
0x03F,
|
||||
0x3B2,
|
||||
0x3B2,
|
||||
0x090,
|
||||
0x022,
|
||||
0x035
|
||||
};
|
||||
|
||||
public static int GetHue( int noto )
|
||||
{
|
||||
if ( noto < 0 || noto >= Hues.Length )
|
||||
return 0;
|
||||
public static int GetHue(int noto)
|
||||
{
|
||||
if (noto < 0 || noto >= Hues.Length)
|
||||
return 0;
|
||||
|
||||
return Hues[noto];
|
||||
}
|
||||
return Hues[noto];
|
||||
}
|
||||
|
||||
public static int Compute( Mobile source, Mobile target )
|
||||
{
|
||||
return Handler?.Invoke( source, target ) ?? CanBeAttacked;
|
||||
}
|
||||
}
|
||||
public static int Compute(Mobile source, Mobile target)
|
||||
{
|
||||
return Handler?.Invoke(source, target) ?? CanBeAttacked;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,176 +18,177 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class ObjectPropertyList : Packet
|
||||
{
|
||||
private int m_Hash;
|
||||
private int m_Strings;
|
||||
public sealed class ObjectPropertyList : Packet
|
||||
{
|
||||
private static byte[] m_Buffer = new byte[1024];
|
||||
private static Encoding m_Encoding = Encoding.Unicode;
|
||||
|
||||
public IEntity Entity { get; }
|
||||
// Each of these are localized to "~1_NOTHING~" which allows the string argument to be used
|
||||
private static int[] m_StringNumbers =
|
||||
{
|
||||
1042971,
|
||||
1070722
|
||||
};
|
||||
|
||||
public int Hash => 0x40000000 + m_Hash;
|
||||
private int m_Hash;
|
||||
private int m_Strings;
|
||||
|
||||
public int Header { get; set; }
|
||||
public ObjectPropertyList(IEntity e) : base(0xD6)
|
||||
{
|
||||
EnsureCapacity(128);
|
||||
|
||||
public string HeaderArgs { get; set; }
|
||||
Entity = e;
|
||||
|
||||
public static bool Enabled { get; set; }
|
||||
m_Stream.Write((short)1);
|
||||
m_Stream.Write(e.Serial);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write(e.Serial);
|
||||
}
|
||||
|
||||
public ObjectPropertyList( IEntity e ) : base( 0xD6 )
|
||||
{
|
||||
EnsureCapacity( 128 );
|
||||
public IEntity Entity{ get; }
|
||||
|
||||
Entity = e;
|
||||
public int Hash => 0x40000000 + m_Hash;
|
||||
|
||||
m_Stream.Write( (short) 1 );
|
||||
m_Stream.Write( (int) e.Serial );
|
||||
m_Stream.Write( (byte) 0 );
|
||||
m_Stream.Write( (byte) 0 );
|
||||
m_Stream.Write( (int) e.Serial );
|
||||
}
|
||||
public int Header{ get; set; }
|
||||
|
||||
public void Add( int number )
|
||||
{
|
||||
if ( number == 0 )
|
||||
return;
|
||||
public string HeaderArgs{ get; set; }
|
||||
|
||||
AddHash( number );
|
||||
public static bool Enabled{ get; set; }
|
||||
|
||||
if ( Header == 0 )
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = "";
|
||||
}
|
||||
public void Add(int number)
|
||||
{
|
||||
if (number == 0)
|
||||
return;
|
||||
|
||||
m_Stream.Write( number );
|
||||
m_Stream.Write( (short) 0 );
|
||||
}
|
||||
AddHash(number);
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
m_Stream.Write( (int) 0 );
|
||||
if (Header == 0)
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = "";
|
||||
}
|
||||
|
||||
m_Stream.Seek( 11, System.IO.SeekOrigin.Begin );
|
||||
m_Stream.Write( (int) m_Hash );
|
||||
}
|
||||
m_Stream.Write(number);
|
||||
m_Stream.Write((short)0);
|
||||
}
|
||||
|
||||
private static byte[] m_Buffer = new byte[1024];
|
||||
private static Encoding m_Encoding = Encoding.Unicode;
|
||||
public void Terminate()
|
||||
{
|
||||
m_Stream.Write(0);
|
||||
|
||||
public void AddHash( int val )
|
||||
{
|
||||
m_Hash ^= (val & 0x3FFFFFF);
|
||||
m_Hash ^= (val >> 26) & 0x3F;
|
||||
}
|
||||
m_Stream.Seek(11, SeekOrigin.Begin);
|
||||
m_Stream.Write(m_Hash);
|
||||
}
|
||||
|
||||
public void Add( int number, string arguments )
|
||||
{
|
||||
if ( number == 0 )
|
||||
return;
|
||||
public void AddHash(int val)
|
||||
{
|
||||
m_Hash ^= val & 0x3FFFFFF;
|
||||
m_Hash ^= (val >> 26) & 0x3F;
|
||||
}
|
||||
|
||||
if ( arguments == null )
|
||||
arguments = "";
|
||||
public void Add(int number, string arguments)
|
||||
{
|
||||
if (number == 0)
|
||||
return;
|
||||
|
||||
if ( Header == 0 )
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = arguments;
|
||||
}
|
||||
if (arguments == null)
|
||||
arguments = "";
|
||||
|
||||
AddHash( number );
|
||||
AddHash( arguments.GetHashCode() );
|
||||
if (Header == 0)
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = arguments;
|
||||
}
|
||||
|
||||
m_Stream.Write( number );
|
||||
AddHash(number);
|
||||
AddHash(arguments.GetHashCode());
|
||||
|
||||
int byteCount = m_Encoding.GetByteCount( arguments );
|
||||
m_Stream.Write(number);
|
||||
|
||||
if ( byteCount > m_Buffer.Length )
|
||||
m_Buffer = new byte[byteCount];
|
||||
int byteCount = m_Encoding.GetByteCount(arguments);
|
||||
|
||||
byteCount = m_Encoding.GetBytes( arguments, 0, arguments.Length, m_Buffer, 0 );
|
||||
if (byteCount > m_Buffer.Length)
|
||||
m_Buffer = new byte[byteCount];
|
||||
|
||||
m_Stream.Write( (short) byteCount );
|
||||
m_Stream.Write( m_Buffer, 0, byteCount );
|
||||
}
|
||||
byteCount = m_Encoding.GetBytes(arguments, 0, arguments.Length, m_Buffer, 0);
|
||||
|
||||
public void Add( int number, string format, object arg0 )
|
||||
{
|
||||
Add( number, string.Format( format, arg0 ) );
|
||||
}
|
||||
m_Stream.Write((short)byteCount);
|
||||
m_Stream.Write(m_Buffer, 0, byteCount);
|
||||
}
|
||||
|
||||
public void Add( int number, string format, object arg0, object arg1 )
|
||||
{
|
||||
Add( number, string.Format( format, arg0, arg1 ) );
|
||||
}
|
||||
public void Add(int number, string format, object arg0)
|
||||
{
|
||||
Add(number, string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public void Add( int number, string format, object arg0, object arg1, object arg2 )
|
||||
{
|
||||
Add( number, string.Format( format, arg0, arg1, arg2 ) );
|
||||
}
|
||||
public void Add(int number, string format, object arg0, object arg1)
|
||||
{
|
||||
Add(number, string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public void Add( int number, string format, params object[] args )
|
||||
{
|
||||
Add( number, string.Format( format, args ) );
|
||||
}
|
||||
public void Add(int number, string format, object arg0, object arg1, object arg2)
|
||||
{
|
||||
Add(number, string.Format(format, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
// Each of these are localized to "~1_NOTHING~" which allows the string argument to be used
|
||||
private static int[] m_StringNumbers = {
|
||||
1042971,
|
||||
1070722
|
||||
};
|
||||
public void Add(int number, string format, params object[] args)
|
||||
{
|
||||
Add(number, string.Format(format, args));
|
||||
}
|
||||
|
||||
private int GetStringNumber()
|
||||
{
|
||||
return m_StringNumbers[m_Strings++ % m_StringNumbers.Length];
|
||||
}
|
||||
private int GetStringNumber()
|
||||
{
|
||||
return m_StringNumbers[m_Strings++ % m_StringNumbers.Length];
|
||||
}
|
||||
|
||||
public void Add( string text )
|
||||
{
|
||||
Add( GetStringNumber(), text );
|
||||
}
|
||||
public void Add(string text)
|
||||
{
|
||||
Add(GetStringNumber(), text);
|
||||
}
|
||||
|
||||
public void Add( string format, string arg0 )
|
||||
{
|
||||
Add( GetStringNumber(), string.Format( format, arg0 ) );
|
||||
}
|
||||
public void Add(string format, string arg0)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public void Add( string format, string arg0, string arg1 )
|
||||
{
|
||||
Add( GetStringNumber(), string.Format( format, arg0, arg1 ) );
|
||||
}
|
||||
public void Add(string format, string arg0, string arg1)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public void Add( string format, string arg0, string arg1, string arg2 )
|
||||
{
|
||||
Add( GetStringNumber(), string.Format( format, arg0, arg1, arg2 ) );
|
||||
}
|
||||
public void Add(string format, string arg0, string arg1, string arg2)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
public void Add( string format, params object[] args )
|
||||
{
|
||||
Add( GetStringNumber(), string.Format( format, args ) );
|
||||
}
|
||||
}
|
||||
public void Add(string format, params object[] args)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class OPLInfo : Packet
|
||||
{
|
||||
/*public OPLInfo( ObjectPropertyList list ) : base( 0xBF )
|
||||
{
|
||||
EnsureCapacity( 13 );
|
||||
public sealed class OPLInfo : Packet
|
||||
{
|
||||
/*public OPLInfo( ObjectPropertyList list ) : base( 0xBF )
|
||||
{
|
||||
EnsureCapacity( 13 );
|
||||
|
||||
m_Stream.Write( (short) 0x10 );
|
||||
m_Stream.Write( (int) list.Entity.Serial );
|
||||
m_Stream.Write( (int) list.Hash );
|
||||
}*/
|
||||
m_Stream.Write( (short) 0x10 );
|
||||
m_Stream.Write( (int) list.Entity.Serial );
|
||||
m_Stream.Write( (int) list.Hash );
|
||||
}*/
|
||||
|
||||
public OPLInfo( ObjectPropertyList list ) : base( 0xDC, 9 )
|
||||
{
|
||||
m_Stream.Write( (int) list.Entity.Serial );
|
||||
m_Stream.Write( (int) list.Hash );
|
||||
}
|
||||
}
|
||||
public OPLInfo(ObjectPropertyList list) : base(0xDC, 9)
|
||||
{
|
||||
m_Stream.Write(list.Entity.Serial);
|
||||
m_Stream.Write(list.Hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,16 +20,16 @@
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class PartyCommands
|
||||
{
|
||||
public static PartyCommands Handler { get; set; }
|
||||
public abstract class PartyCommands
|
||||
{
|
||||
public static PartyCommands Handler{ get; set; }
|
||||
|
||||
public abstract void OnAdd( Mobile from );
|
||||
public abstract void OnRemove( Mobile from, Mobile target );
|
||||
public abstract void OnPrivateMessage( Mobile from, Mobile target, string text );
|
||||
public abstract void OnPublicMessage( Mobile from, string text );
|
||||
public abstract void OnSetCanLoot( Mobile from, bool canLoot );
|
||||
public abstract void OnAccept( Mobile from, Mobile leader );
|
||||
public abstract void OnDecline( Mobile from, Mobile leader );
|
||||
}
|
||||
public abstract void OnAdd(Mobile from);
|
||||
public abstract void OnRemove(Mobile from, Mobile target);
|
||||
public abstract void OnPrivateMessage(Mobile from, Mobile target, string text);
|
||||
public abstract void OnPublicMessage(Mobile from, string text);
|
||||
public abstract void OnSetCanLoot(Mobile from, bool canLoot);
|
||||
public abstract void OnAccept(Mobile from, Mobile leader);
|
||||
public abstract void OnDecline(Mobile from, Mobile leader);
|
||||
}
|
||||
}
|
||||
|
|
@ -20,62 +20,63 @@
|
|||
|
||||
using System.IO;
|
||||
|
||||
namespace Server {
|
||||
public sealed class BinaryMemoryWriter : BinaryFileWriter {
|
||||
private MemoryStream stream;
|
||||
namespace Server
|
||||
{
|
||||
public sealed class BinaryMemoryWriter : BinaryFileWriter
|
||||
{
|
||||
private static byte[] indexBuffer;
|
||||
private MemoryStream stream;
|
||||
|
||||
protected override int BufferSize => 512;
|
||||
public BinaryMemoryWriter()
|
||||
: base(new MemoryStream(512), true)
|
||||
{
|
||||
stream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
|
||||
public BinaryMemoryWriter()
|
||||
: base( new MemoryStream( 512 ), true ) {
|
||||
stream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
protected override int BufferSize => 512;
|
||||
|
||||
private static byte[] indexBuffer;
|
||||
public int CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile, int typeCode, int serial)
|
||||
{
|
||||
Flush();
|
||||
|
||||
public int CommitTo( SequentialFileWriter dataFile, SequentialFileWriter indexFile, int typeCode, int serial ) {
|
||||
Flush();
|
||||
byte[] buffer = stream.GetBuffer();
|
||||
int length = (int)stream.Length;
|
||||
|
||||
byte[] buffer = stream.GetBuffer();
|
||||
int length = ( int ) stream.Length;
|
||||
long position = dataFile.Position;
|
||||
|
||||
long position = dataFile.Position;
|
||||
dataFile.Write(buffer, 0, length);
|
||||
|
||||
dataFile.Write( buffer, 0, length );
|
||||
if (indexBuffer == null) indexBuffer = new byte[20];
|
||||
|
||||
if ( indexBuffer == null ) {
|
||||
indexBuffer = new byte[20];
|
||||
}
|
||||
indexBuffer[0] = (byte)typeCode;
|
||||
indexBuffer[1] = (byte)(typeCode >> 8);
|
||||
indexBuffer[2] = (byte)(typeCode >> 16);
|
||||
indexBuffer[3] = (byte)(typeCode >> 24);
|
||||
|
||||
indexBuffer[0] = ( byte ) ( typeCode );
|
||||
indexBuffer[1] = ( byte ) ( typeCode >> 8 );
|
||||
indexBuffer[2] = ( byte ) ( typeCode >> 16 );
|
||||
indexBuffer[3] = ( byte ) ( typeCode >> 24 );
|
||||
indexBuffer[4] = (byte)serial;
|
||||
indexBuffer[5] = (byte)(serial >> 8);
|
||||
indexBuffer[6] = (byte)(serial >> 16);
|
||||
indexBuffer[7] = (byte)(serial >> 24);
|
||||
|
||||
indexBuffer[4] = ( byte ) ( serial );
|
||||
indexBuffer[5] = ( byte ) ( serial >> 8 );
|
||||
indexBuffer[6] = ( byte ) ( serial >> 16 );
|
||||
indexBuffer[7] = ( byte ) ( serial >> 24 );
|
||||
indexBuffer[8] = (byte)position;
|
||||
indexBuffer[9] = (byte)(position >> 8);
|
||||
indexBuffer[10] = (byte)(position >> 16);
|
||||
indexBuffer[11] = (byte)(position >> 24);
|
||||
indexBuffer[12] = (byte)(position >> 32);
|
||||
indexBuffer[13] = (byte)(position >> 40);
|
||||
indexBuffer[14] = (byte)(position >> 48);
|
||||
indexBuffer[15] = (byte)(position >> 56);
|
||||
|
||||
indexBuffer[8] = ( byte ) ( position );
|
||||
indexBuffer[9] = ( byte ) ( position >> 8 );
|
||||
indexBuffer[10] = ( byte ) ( position >> 16 );
|
||||
indexBuffer[11] = ( byte ) ( position >> 24 );
|
||||
indexBuffer[12] = ( byte ) ( position >> 32 );
|
||||
indexBuffer[13] = ( byte ) ( position >> 40 );
|
||||
indexBuffer[14] = ( byte ) ( position >> 48 );
|
||||
indexBuffer[15] = ( byte ) ( position >> 56 );
|
||||
indexBuffer[16] = (byte)length;
|
||||
indexBuffer[17] = (byte)(length >> 8);
|
||||
indexBuffer[18] = (byte)(length >> 16);
|
||||
indexBuffer[19] = (byte)(length >> 24);
|
||||
|
||||
indexBuffer[16] = ( byte ) ( length );
|
||||
indexBuffer[17] = ( byte ) ( length >> 8 );
|
||||
indexBuffer[18] = ( byte ) ( length >> 16 );
|
||||
indexBuffer[19] = ( byte ) ( length >> 24 );
|
||||
indexFile.Write(indexBuffer, 0, indexBuffer.Length);
|
||||
|
||||
indexFile.Write( indexBuffer, 0, indexBuffer.Length );
|
||||
stream.SetLength(0);
|
||||
|
||||
stream.SetLength( 0 );
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,31 +20,29 @@
|
|||
|
||||
using System.Threading;
|
||||
|
||||
namespace Server {
|
||||
public sealed class DualSaveStrategy : StandardSaveStrategy {
|
||||
public override string Name => "Dual";
|
||||
namespace Server
|
||||
{
|
||||
public sealed class DualSaveStrategy : StandardSaveStrategy
|
||||
{
|
||||
public override string Name => "Dual";
|
||||
|
||||
public DualSaveStrategy() {
|
||||
}
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
PermitBackgroundWrite = permitBackgroundWrite;
|
||||
|
||||
public override void Save( SaveMetrics metrics, bool permitBackgroundWrite )
|
||||
{
|
||||
PermitBackgroundWrite = permitBackgroundWrite;
|
||||
Thread saveThread = new Thread(delegate() { SaveItems(metrics); });
|
||||
|
||||
Thread saveThread = new Thread( delegate() {
|
||||
SaveItems(metrics);
|
||||
} );
|
||||
saveThread.Name = "Item Save Subset";
|
||||
saveThread.Start();
|
||||
|
||||
saveThread.Name = "Item Save Subset";
|
||||
saveThread.Start();
|
||||
SaveMobiles(metrics);
|
||||
SaveGuilds(metrics);
|
||||
|
||||
SaveMobiles(metrics);
|
||||
SaveGuilds(metrics);
|
||||
saveThread.Join();
|
||||
|
||||
saveThread.Join();
|
||||
|
||||
if (permitBackgroundWrite && UseSequentialWriters) //If we're permitted to write in the background, but we don't anyways, then notify.
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (permitBackgroundWrite && UseSequentialWriters
|
||||
) //If we're permitted to write in the background, but we don't anyways, then notify.
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,278 +20,270 @@
|
|||
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using System.Collections.Concurrent;
|
||||
using Server.Guilds;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class DynamicSaveStrategy : SaveStrategy
|
||||
{
|
||||
public override string Name => "Dynamic";
|
||||
|
||||
private SaveMetrics _metrics;
|
||||
|
||||
private SequentialFileWriter _itemData, _itemIndex;
|
||||
private SequentialFileWriter _mobileData, _mobileIndex;
|
||||
private SequentialFileWriter _guildData, _guildIndex;
|
||||
|
||||
private ConcurrentBag<Item> _decayBag;
|
||||
|
||||
private BlockingCollection<QueuedMemoryWriter> _itemThreadWriters;
|
||||
private BlockingCollection<QueuedMemoryWriter> _mobileThreadWriters;
|
||||
private BlockingCollection<QueuedMemoryWriter> _guildThreadWriters;
|
||||
|
||||
public DynamicSaveStrategy()
|
||||
{
|
||||
_decayBag = new ConcurrentBag<Item>();
|
||||
_itemThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_mobileThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_guildThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
}
|
||||
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
_metrics = metrics;
|
||||
|
||||
OpenFiles();
|
||||
|
||||
Task[] saveTasks = new Task[3];
|
||||
|
||||
saveTasks[0] = SaveItems();
|
||||
saveTasks[1] = SaveMobiles();
|
||||
saveTasks[2] = SaveGuilds();
|
||||
|
||||
SaveTypeDatabases();
|
||||
public sealed class DynamicSaveStrategy : SaveStrategy
|
||||
{
|
||||
private ConcurrentBag<Item> _decayBag;
|
||||
private SequentialFileWriter _guildData, _guildIndex;
|
||||
private BlockingCollection<QueuedMemoryWriter> _guildThreadWriters;
|
||||
|
||||
private SequentialFileWriter _itemData, _itemIndex;
|
||||
|
||||
private BlockingCollection<QueuedMemoryWriter> _itemThreadWriters;
|
||||
|
||||
private SaveMetrics _metrics;
|
||||
private SequentialFileWriter _mobileData, _mobileIndex;
|
||||
private BlockingCollection<QueuedMemoryWriter> _mobileThreadWriters;
|
||||
|
||||
public DynamicSaveStrategy()
|
||||
{
|
||||
_decayBag = new ConcurrentBag<Item>();
|
||||
_itemThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_mobileThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_guildThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
}
|
||||
|
||||
public override string Name => "Dynamic";
|
||||
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
_metrics = metrics;
|
||||
|
||||
OpenFiles();
|
||||
|
||||
Task[] saveTasks = new Task[3];
|
||||
|
||||
saveTasks[0] = SaveItems();
|
||||
saveTasks[1] = SaveMobiles();
|
||||
saveTasks[2] = SaveGuilds();
|
||||
|
||||
if (permitBackgroundWrite)
|
||||
{
|
||||
//This option makes it finish the writing to disk in the background, continuing even after Save() returns.
|
||||
Task.Factory.ContinueWhenAll(saveTasks, _ =>
|
||||
{
|
||||
CloseFiles();
|
||||
SaveTypeDatabases();
|
||||
|
||||
World.NotifyDiskWriteComplete();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.WaitAll(saveTasks); //Waits for the completion of all of the tasks(committing to disk)
|
||||
CloseFiles();
|
||||
}
|
||||
}
|
||||
if (permitBackgroundWrite)
|
||||
{
|
||||
//This option makes it finish the writing to disk in the background, continuing even after Save() returns.
|
||||
Task.Factory.ContinueWhenAll(saveTasks, _ =>
|
||||
{
|
||||
CloseFiles();
|
||||
|
||||
private Task StartCommitTask(BlockingCollection<QueuedMemoryWriter> threadWriter, SequentialFileWriter data, SequentialFileWriter index)
|
||||
{
|
||||
Task commitTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (!(threadWriter.IsCompleted))
|
||||
{
|
||||
QueuedMemoryWriter writer;
|
||||
World.NotifyDiskWriteComplete();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.WaitAll(saveTasks); //Waits for the completion of all of the tasks(committing to disk)
|
||||
CloseFiles();
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
writer = threadWriter.Take();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//Per MSDN, it's fine if we're here, successful completion of adding can rarely put us into this state.
|
||||
break;
|
||||
}
|
||||
private Task StartCommitTask(BlockingCollection<QueuedMemoryWriter> threadWriter, SequentialFileWriter data,
|
||||
SequentialFileWriter index)
|
||||
{
|
||||
Task commitTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (!threadWriter.IsCompleted)
|
||||
{
|
||||
QueuedMemoryWriter writer;
|
||||
|
||||
writer.CommitTo(data, index);
|
||||
}
|
||||
});
|
||||
try
|
||||
{
|
||||
writer = threadWriter.Take();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//Per MSDN, it's fine if we're here, successful completion of adding can rarely put us into this state.
|
||||
break;
|
||||
}
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
writer.CommitTo(data, index);
|
||||
}
|
||||
});
|
||||
|
||||
private Task SaveItems()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_itemThreadWriters, _itemData, _itemIndex);
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
IEnumerable<Item> items = World.Items.Values;
|
||||
private Task SaveItems()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_itemThreadWriters, _itemData, _itemIndex);
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(items, () => new QueuedMemoryWriter(),
|
||||
(Item item, ParallelLoopState state, QueuedMemoryWriter writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
IEnumerable<Item> items = World.Items.Values;
|
||||
|
||||
item.Serialize(writer);
|
||||
//Start the producer.
|
||||
Parallel.ForEach(items, () => new QueuedMemoryWriter(),
|
||||
(item, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
item.Serialize(writer);
|
||||
|
||||
writer.QueueForIndex(item, size);
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.UtcNow > (item.LastMoved + item.DecayTime))
|
||||
{
|
||||
_decayBag.Add(item);
|
||||
}
|
||||
writer.QueueForIndex(item, size);
|
||||
|
||||
_metrics?.OnItemSaved(size);
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal &&
|
||||
DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayBag.Add(item);
|
||||
|
||||
return writer;
|
||||
},
|
||||
(writer) =>
|
||||
{
|
||||
writer.Flush();
|
||||
_metrics?.OnItemSaved(size);
|
||||
|
||||
_itemThreadWriters.Add(writer);
|
||||
});
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_itemThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
_itemThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
_itemThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
|
||||
private Task SaveMobiles()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask( _mobileThreadWriters, _mobileData, _mobileIndex );
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
IEnumerable<Mobile> mobiles = World.Mobiles.Values;
|
||||
private Task SaveMobiles()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_mobileThreadWriters, _mobileData, _mobileIndex);
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(mobiles, () => new QueuedMemoryWriter(),
|
||||
(Mobile mobile, ParallelLoopState state, QueuedMemoryWriter writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
IEnumerable<Mobile> mobiles = World.Mobiles.Values;
|
||||
|
||||
mobile.Serialize(writer);
|
||||
//Start the producer.
|
||||
Parallel.ForEach(mobiles, () => new QueuedMemoryWriter(),
|
||||
(mobile, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
mobile.Serialize(writer);
|
||||
|
||||
writer.QueueForIndex(mobile, size);
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
_metrics?.OnMobileSaved(size);
|
||||
writer.QueueForIndex(mobile, size);
|
||||
|
||||
return writer;
|
||||
},
|
||||
(writer) =>
|
||||
{
|
||||
writer.Flush();
|
||||
_metrics?.OnMobileSaved(size);
|
||||
|
||||
_mobileThreadWriters.Add(writer);
|
||||
});
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_mobileThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task tell the consumer that we're done
|
||||
_mobileThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
_mobileThreadWriters
|
||||
.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task tell the consumer that we're done
|
||||
|
||||
private Task SaveGuilds()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_guildThreadWriters, _guildData, _guildIndex);
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
IEnumerable<BaseGuild> guilds = BaseGuild.List.Values;
|
||||
private Task SaveGuilds()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_guildThreadWriters, _guildData, _guildIndex);
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(guilds, () => new QueuedMemoryWriter(),
|
||||
(BaseGuild guild, ParallelLoopState state, QueuedMemoryWriter writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
IEnumerable<BaseGuild> guilds = BaseGuild.List.Values;
|
||||
|
||||
guild.Serialize(writer);
|
||||
//Start the producer.
|
||||
Parallel.ForEach(guilds, () => new QueuedMemoryWriter(),
|
||||
(guild, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
int size = (int)(writer.Position - startPosition );
|
||||
guild.Serialize(writer);
|
||||
|
||||
writer.QueueForIndex(guild, size);
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
_metrics?.OnGuildSaved(size);
|
||||
writer.QueueForIndex(guild, size);
|
||||
|
||||
return writer;
|
||||
},
|
||||
(writer) =>
|
||||
{
|
||||
writer.Flush();
|
||||
_metrics?.OnGuildSaved(size);
|
||||
|
||||
_guildThreadWriters.Add(writer);
|
||||
});
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_guildThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
_guildThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
_guildThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
Item item;
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
while( _decayBag.TryTake( out item ) )
|
||||
{
|
||||
if ( item.OnDecay() )
|
||||
{
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
Item item;
|
||||
|
||||
private void OpenFiles()
|
||||
{
|
||||
_itemData = new SequentialFileWriter(World.ItemDataPath, _metrics);
|
||||
_itemIndex = new SequentialFileWriter(World.ItemIndexPath, _metrics);
|
||||
while (_decayBag.TryTake(out item))
|
||||
if (item.OnDecay())
|
||||
item.Delete();
|
||||
}
|
||||
|
||||
_mobileData = new SequentialFileWriter(World.MobileDataPath, _metrics);
|
||||
_mobileIndex = new SequentialFileWriter(World.MobileIndexPath, _metrics);
|
||||
private void OpenFiles()
|
||||
{
|
||||
_itemData = new SequentialFileWriter(World.ItemDataPath, _metrics);
|
||||
_itemIndex = new SequentialFileWriter(World.ItemIndexPath, _metrics);
|
||||
|
||||
_guildData = new SequentialFileWriter(World.GuildDataPath, _metrics);
|
||||
_guildIndex = new SequentialFileWriter(World.GuildIndexPath, _metrics);
|
||||
_mobileData = new SequentialFileWriter(World.MobileDataPath, _metrics);
|
||||
_mobileIndex = new SequentialFileWriter(World.MobileIndexPath, _metrics);
|
||||
|
||||
WriteCount(_itemIndex, World.Items.Count);
|
||||
WriteCount(_mobileIndex, World.Mobiles.Count);
|
||||
WriteCount(_guildIndex, BaseGuild.List.Count);
|
||||
}
|
||||
_guildData = new SequentialFileWriter(World.GuildDataPath, _metrics);
|
||||
_guildIndex = new SequentialFileWriter(World.GuildIndexPath, _metrics);
|
||||
|
||||
private void CloseFiles()
|
||||
{
|
||||
_itemData.Close();
|
||||
_itemIndex.Close();
|
||||
WriteCount(_itemIndex, World.Items.Count);
|
||||
WriteCount(_mobileIndex, World.Mobiles.Count);
|
||||
WriteCount(_guildIndex, BaseGuild.List.Count);
|
||||
}
|
||||
|
||||
_mobileData.Close();
|
||||
_mobileIndex.Close();
|
||||
private void CloseFiles()
|
||||
{
|
||||
_itemData.Close();
|
||||
_itemIndex.Close();
|
||||
|
||||
_guildData.Close();
|
||||
_guildIndex.Close();
|
||||
}
|
||||
_mobileData.Close();
|
||||
_mobileIndex.Close();
|
||||
|
||||
private void WriteCount(SequentialFileWriter indexFile, int count)
|
||||
{
|
||||
//Equiv to GenericWriter.Write( (int)count );
|
||||
byte[] buffer = new byte[4];
|
||||
_guildData.Close();
|
||||
_guildIndex.Close();
|
||||
}
|
||||
|
||||
buffer[0] = (byte)(count);
|
||||
buffer[1] = (byte)(count >> 8);
|
||||
buffer[2] = (byte)(count >> 16);
|
||||
buffer[3] = (byte)(count >> 24);
|
||||
private void WriteCount(SequentialFileWriter indexFile, int count)
|
||||
{
|
||||
//Equiv to GenericWriter.Write( (int)count );
|
||||
byte[] buffer = new byte[4];
|
||||
|
||||
indexFile.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
buffer[0] = (byte)count;
|
||||
buffer[1] = (byte)(count >> 8);
|
||||
buffer[2] = (byte)(count >> 16);
|
||||
buffer[3] = (byte)(count >> 24);
|
||||
|
||||
private void SaveTypeDatabases()
|
||||
{
|
||||
SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes);
|
||||
SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes);
|
||||
}
|
||||
indexFile.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private void SaveTypeDatabase(string path, List<Type> types)
|
||||
{
|
||||
BinaryFileWriter bfw = new BinaryFileWriter(path, false);
|
||||
private void SaveTypeDatabases()
|
||||
{
|
||||
SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes);
|
||||
SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes);
|
||||
}
|
||||
|
||||
bfw.Write(types.Count);
|
||||
private void SaveTypeDatabase(string path, List<Type> types)
|
||||
{
|
||||
BinaryFileWriter bfw = new BinaryFileWriter(path, false);
|
||||
|
||||
foreach (Type type in types)
|
||||
{
|
||||
bfw.Write(type.FullName);
|
||||
}
|
||||
bfw.Write(types.Count);
|
||||
|
||||
bfw.Flush();
|
||||
foreach (Type type in types) bfw.Write(type.FullName);
|
||||
|
||||
bfw.Close();
|
||||
}
|
||||
}
|
||||
bfw.Flush();
|
||||
|
||||
}
|
||||
bfw.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,83 +24,89 @@ using System.IO;
|
|||
#if !MONO
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Server {
|
||||
public static class FileOperations {
|
||||
public const int KB = 1024;
|
||||
public const int MB = 1024 * KB;
|
||||
namespace Server
|
||||
{
|
||||
public static class FileOperations
|
||||
{
|
||||
public const int KB = 1024;
|
||||
public const int MB = 1024 * KB;
|
||||
|
||||
#if !MONO
|
||||
private const FileOptions NoBuffering = ( FileOptions ) 0x20000000;
|
||||
public static int BufferSize{ get; set; } = 1 * MB;
|
||||
|
||||
internal static class UnsafeNativeMethods {
|
||||
[DllImport("Kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode, IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
}
|
||||
#endif
|
||||
public static int Concurrency{ get; set; } = 1;
|
||||
|
||||
public static int BufferSize { get; set; } = 1 * MB;
|
||||
public static bool Unbuffered{ get; set; } = true;
|
||||
|
||||
public static int Concurrency { get; set; } = 1;
|
||||
public static bool AreSynchronous => Concurrency < 1;
|
||||
|
||||
public static bool Unbuffered { get; set; } = true;
|
||||
public static bool AreAsynchronous => Concurrency > 0;
|
||||
|
||||
public static bool AreSynchronous => ( Concurrency < 1 );
|
||||
public static FileStream OpenSequentialStream(string path, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
FileOptions options = FileOptions.SequentialScan;
|
||||
|
||||
public static bool AreAsynchronous => ( Concurrency > 0 );
|
||||
|
||||
public static FileStream OpenSequentialStream( string path, FileMode mode, FileAccess access, FileShare share ) {
|
||||
FileOptions options = FileOptions.SequentialScan;
|
||||
|
||||
if ( Concurrency > 0 ) {
|
||||
options |= FileOptions.Asynchronous;
|
||||
}
|
||||
if (Concurrency > 0) options |= FileOptions.Asynchronous;
|
||||
|
||||
#if MONO
|
||||
return new FileStream( path, mode, access, share, bufferSize, options );
|
||||
#else
|
||||
if ( Unbuffered ) {
|
||||
options |= NoBuffering;
|
||||
} else {
|
||||
return new FileStream( path, mode, access, share, BufferSize, options );
|
||||
}
|
||||
if (Unbuffered)
|
||||
options |= NoBuffering;
|
||||
else
|
||||
return new FileStream(path, mode, access, share, BufferSize, options);
|
||||
|
||||
SafeFileHandle fileHandle = UnsafeNativeMethods.CreateFile(path, (int)access, share, IntPtr.Zero, mode, (int)options, IntPtr.Zero);
|
||||
SafeFileHandle fileHandle =
|
||||
UnsafeNativeMethods.CreateFile(path, (int)access, share, IntPtr.Zero, mode, (int)options, IntPtr.Zero);
|
||||
|
||||
if ( fileHandle.IsInvalid ) {
|
||||
throw new IOException();
|
||||
}
|
||||
if (fileHandle.IsInvalid) throw new IOException();
|
||||
|
||||
return new UnbufferedFileStream( fileHandle, access, BufferSize, ( Concurrency > 0 ) );
|
||||
return new UnbufferedFileStream(fileHandle, access, BufferSize, Concurrency > 0);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !MONO
|
||||
private class UnbufferedFileStream : FileStream {
|
||||
private SafeFileHandle fileHandle;
|
||||
private class UnbufferedFileStream : FileStream
|
||||
{
|
||||
private SafeFileHandle fileHandle;
|
||||
|
||||
public UnbufferedFileStream( SafeFileHandle fileHandle, FileAccess access, int bufferSize, bool isAsync )
|
||||
: base( fileHandle, access, bufferSize, isAsync ) {
|
||||
this.fileHandle = fileHandle;
|
||||
}
|
||||
public UnbufferedFileStream(SafeFileHandle fileHandle, FileAccess access, int bufferSize, bool isAsync)
|
||||
: base(fileHandle, access, bufferSize, isAsync)
|
||||
{
|
||||
this.fileHandle = fileHandle;
|
||||
}
|
||||
|
||||
public override void Write( byte[] array, int offset, int count ) {
|
||||
base.Write( array, offset, BufferSize );
|
||||
}
|
||||
public override void Write(byte[] array, int offset, int count)
|
||||
{
|
||||
base.Write(array, offset, BufferSize);
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite( byte[] array, int offset, int numBytes, AsyncCallback userCallback, object stateObject ) {
|
||||
return base.BeginWrite( array, offset, BufferSize, userCallback, stateObject );
|
||||
}
|
||||
public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback,
|
||||
object stateObject)
|
||||
{
|
||||
return base.BeginWrite(array, offset, BufferSize, userCallback, stateObject);
|
||||
}
|
||||
|
||||
protected override void Dispose( bool disposing ) {
|
||||
if ( !fileHandle.IsClosed ) {
|
||||
fileHandle.Close();
|
||||
}
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!fileHandle.IsClosed) fileHandle.Close();
|
||||
|
||||
base.Dispose( disposing );
|
||||
}
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#if !MONO
|
||||
private const FileOptions NoBuffering = (FileOptions)0x20000000;
|
||||
|
||||
internal static class UnsafeNativeMethods
|
||||
{
|
||||
[DllImport("Kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode,
|
||||
IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
@ -23,212 +23,210 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server {
|
||||
public delegate void FileCommitCallback( FileQueue.Chunk chunk );
|
||||
namespace Server
|
||||
{
|
||||
public delegate void FileCommitCallback(FileQueue.Chunk chunk);
|
||||
|
||||
public sealed class FileQueue : IDisposable {
|
||||
public sealed class Chunk {
|
||||
private FileQueue owner;
|
||||
private int slot;
|
||||
public sealed class FileQueue : IDisposable
|
||||
{
|
||||
private static int bufferSize;
|
||||
private static BufferPool bufferPool;
|
||||
|
||||
private int offset;
|
||||
private Chunk[] active;
|
||||
private int activeCount;
|
||||
private Page buffered;
|
||||
|
||||
public byte[] Buffer { get; }
|
||||
private FileCommitCallback callback;
|
||||
|
||||
public int Offset => 0;
|
||||
private ManualResetEvent idle;
|
||||
|
||||
public int Size { get; }
|
||||
private Queue<Page> pending;
|
||||
|
||||
public Chunk( FileQueue owner, int slot, byte[] buffer, int offset, int size ) {
|
||||
this.owner = owner;
|
||||
this.slot = slot;
|
||||
private object syncRoot;
|
||||
|
||||
this.Buffer = buffer;
|
||||
this.offset = offset;
|
||||
this.Size = size;
|
||||
}
|
||||
static FileQueue()
|
||||
{
|
||||
bufferSize = FileOperations.BufferSize;
|
||||
bufferPool = new BufferPool("File Buffers", 64, bufferSize);
|
||||
}
|
||||
|
||||
public void Commit() {
|
||||
owner.Commit( this, slot );
|
||||
}
|
||||
}
|
||||
public FileQueue(int concurrentWrites, FileCommitCallback callback)
|
||||
{
|
||||
if (concurrentWrites < 1) throw new ArgumentOutOfRangeException("concurrentWrites");
|
||||
|
||||
private struct Page {
|
||||
public byte[] buffer;
|
||||
public int length;
|
||||
}
|
||||
if (bufferSize < 1) throw new ArgumentOutOfRangeException("bufferSize");
|
||||
if (callback == null) throw new ArgumentNullException("callback");
|
||||
|
||||
private static int bufferSize;
|
||||
private static BufferPool bufferPool;
|
||||
syncRoot = new object();
|
||||
|
||||
static FileQueue() {
|
||||
bufferSize = FileOperations.BufferSize;
|
||||
bufferPool = new BufferPool( "File Buffers", 64, bufferSize );
|
||||
}
|
||||
active = new Chunk[concurrentWrites];
|
||||
pending = new Queue<Page>();
|
||||
|
||||
private object syncRoot;
|
||||
this.callback = callback;
|
||||
|
||||
private Chunk[] active;
|
||||
private int activeCount;
|
||||
idle = new ManualResetEvent(true);
|
||||
}
|
||||
|
||||
private Queue<Page> pending;
|
||||
private Page buffered;
|
||||
public long Position{ get; private set; }
|
||||
|
||||
private FileCommitCallback callback;
|
||||
public void Dispose()
|
||||
{
|
||||
if (idle != null)
|
||||
{
|
||||
idle.Close();
|
||||
idle = null;
|
||||
}
|
||||
}
|
||||
|
||||
private ManualResetEvent idle;
|
||||
private void Append(Page page)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (activeCount == 0) idle.Reset();
|
||||
|
||||
public long Position { get; private set; }
|
||||
++activeCount;
|
||||
|
||||
public FileQueue( int concurrentWrites, FileCommitCallback callback ) {
|
||||
if ( concurrentWrites < 1 ) {
|
||||
throw new ArgumentOutOfRangeException( "concurrentWrites" );
|
||||
}
|
||||
for (int slot = 0; slot < active.Length; ++slot)
|
||||
if (active[slot] == null)
|
||||
{
|
||||
active[slot] = new Chunk(this, slot, page.buffer, 0, page.length);
|
||||
|
||||
if ( bufferSize < 1 ) {
|
||||
throw new ArgumentOutOfRangeException( "bufferSize" );
|
||||
}
|
||||
if ( callback == null ) {
|
||||
throw new ArgumentNullException( "callback" );
|
||||
}
|
||||
callback(active[slot]);
|
||||
|
||||
syncRoot = new object();
|
||||
return;
|
||||
}
|
||||
|
||||
active = new Chunk[concurrentWrites];
|
||||
pending = new Queue<Page>();
|
||||
pending.Enqueue(page);
|
||||
}
|
||||
}
|
||||
|
||||
this.callback = callback;
|
||||
public void Flush()
|
||||
{
|
||||
if (buffered.buffer != null)
|
||||
{
|
||||
Append(buffered);
|
||||
|
||||
idle = new ManualResetEvent( true );
|
||||
}
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
|
||||
private void Append( Page page ) {
|
||||
lock ( syncRoot ) {
|
||||
if ( activeCount == 0 ) {
|
||||
idle.Reset();
|
||||
}
|
||||
/*lock ( syncRoot ) {
|
||||
if ( pending.Count > 0 ) {
|
||||
idle.Reset();
|
||||
}
|
||||
|
||||
++activeCount;
|
||||
for ( int slot = 0; slot < active.Length && pending.Count > 0; ++slot ) {
|
||||
if ( active[slot] == null ) {
|
||||
Page page = pending.Dequeue();
|
||||
|
||||
for ( int slot = 0; slot < active.Length; ++slot ) {
|
||||
if ( active[slot] == null ) {
|
||||
active[slot] = new Chunk( this, slot, page.buffer, 0, page.length );
|
||||
active[slot] = new Chunk( this, slot, page.buffer, 0, page.length );
|
||||
|
||||
callback( active[slot] );
|
||||
++activeCount;
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
callback( active[slot] );
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
pending.Enqueue( page );
|
||||
}
|
||||
}
|
||||
idle.WaitOne();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
if ( idle != null ) {
|
||||
idle.Close();
|
||||
idle = null;
|
||||
}
|
||||
}
|
||||
private void Commit(Chunk chunk, int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= active.Length) throw new ArgumentOutOfRangeException("slot");
|
||||
|
||||
public void Flush() {
|
||||
if ( buffered.buffer != null ) {
|
||||
Append( buffered );
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (active[slot] != chunk) throw new ArgumentException();
|
||||
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
bufferPool.ReleaseBuffer(chunk.Buffer);
|
||||
|
||||
/*lock ( syncRoot ) {
|
||||
if ( pending.Count > 0 ) {
|
||||
idle.Reset();
|
||||
}
|
||||
if (pending.Count > 0)
|
||||
{
|
||||
Page page = pending.Dequeue();
|
||||
|
||||
for ( int slot = 0; slot < active.Length && pending.Count > 0; ++slot ) {
|
||||
if ( active[slot] == null ) {
|
||||
Page page = pending.Dequeue();
|
||||
active[slot] = new Chunk(this, slot, page.buffer, 0, page.length);
|
||||
|
||||
active[slot] = new Chunk( this, slot, page.buffer, 0, page.length );
|
||||
callback(active[slot]);
|
||||
}
|
||||
else
|
||||
{
|
||||
active[slot] = null;
|
||||
}
|
||||
|
||||
++activeCount;
|
||||
--activeCount;
|
||||
|
||||
callback( active[slot] );
|
||||
}
|
||||
}
|
||||
}*/
|
||||
if (activeCount == 0) idle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
idle.WaitOne();
|
||||
}
|
||||
public void Enqueue(byte[] buffer, int offset, int size)
|
||||
{
|
||||
if (buffer == null) throw new ArgumentNullException("buffer");
|
||||
|
||||
private void Commit( Chunk chunk, int slot ) {
|
||||
if ( slot < 0 || slot >= active.Length ) {
|
||||
throw new ArgumentOutOfRangeException( "slot" );
|
||||
}
|
||||
if (offset < 0) throw new ArgumentOutOfRangeException("offset");
|
||||
if (size < 0) throw new ArgumentOutOfRangeException("size");
|
||||
if (buffer.Length - offset < size) throw new ArgumentException();
|
||||
|
||||
lock ( syncRoot ) {
|
||||
if ( active[slot] != chunk ) {
|
||||
throw new ArgumentException();
|
||||
}
|
||||
Position += size;
|
||||
|
||||
bufferPool.ReleaseBuffer( chunk.Buffer );
|
||||
while (size > 0)
|
||||
{
|
||||
if (buffered.buffer == null) buffered.buffer = bufferPool.AcquireBuffer();
|
||||
|
||||
if ( pending.Count > 0 ) {
|
||||
Page page = pending.Dequeue();
|
||||
byte[] page = buffered.buffer; // buffer page
|
||||
int pageSpace = page.Length - buffered.length; // available bytes in page
|
||||
int byteCount = size > pageSpace ? pageSpace : size; // how many bytes we can copy over
|
||||
|
||||
active[slot] = new Chunk( this, slot, page.buffer, 0, page.length );
|
||||
Buffer.BlockCopy(buffer, offset, page, buffered.length, byteCount);
|
||||
|
||||
callback( active[slot] );
|
||||
} else {
|
||||
active[slot] = null;
|
||||
}
|
||||
buffered.length += byteCount;
|
||||
offset += byteCount;
|
||||
size -= byteCount;
|
||||
|
||||
--activeCount;
|
||||
if (buffered.length == page.Length)
|
||||
{
|
||||
// page full
|
||||
Append(buffered);
|
||||
|
||||
if ( activeCount == 0 ) {
|
||||
idle.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue( byte[] buffer, int offset, int size ) {
|
||||
if ( buffer == null ) {
|
||||
throw new ArgumentNullException( "buffer" );
|
||||
}
|
||||
public sealed class Chunk
|
||||
{
|
||||
private int offset;
|
||||
private FileQueue owner;
|
||||
private int slot;
|
||||
|
||||
if ( offset < 0 ) {
|
||||
throw new ArgumentOutOfRangeException( "offset" );
|
||||
}
|
||||
if ( size < 0 ) {
|
||||
throw new ArgumentOutOfRangeException( "size" );
|
||||
}
|
||||
if ( ( buffer.Length - offset ) < size ) {
|
||||
throw new ArgumentException();
|
||||
}
|
||||
public Chunk(FileQueue owner, int slot, byte[] buffer, int offset, int size)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.slot = slot;
|
||||
|
||||
Position += size;
|
||||
Buffer = buffer;
|
||||
this.offset = offset;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
while ( size > 0 ) {
|
||||
if ( buffered.buffer == null ) { // nothing yet buffered
|
||||
buffered.buffer = bufferPool.AcquireBuffer();
|
||||
}
|
||||
public byte[] Buffer{ get; }
|
||||
|
||||
byte[] page = buffered.buffer; // buffer page
|
||||
int pageSpace = page.Length - buffered.length; // available bytes in page
|
||||
int byteCount = ( size > pageSpace ? pageSpace : size ); // how many bytes we can copy over
|
||||
public int Offset => 0;
|
||||
|
||||
Buffer.BlockCopy( buffer, offset, page, buffered.length, byteCount );
|
||||
public int Size{ get; }
|
||||
|
||||
buffered.length += byteCount;
|
||||
offset += byteCount;
|
||||
size -= byteCount;
|
||||
public void Commit()
|
||||
{
|
||||
owner.Commit(this, slot);
|
||||
}
|
||||
}
|
||||
|
||||
if ( buffered.length == page.Length ) { // page full
|
||||
Append( buffered );
|
||||
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private struct Page
|
||||
{
|
||||
public byte[] buffer;
|
||||
public int length;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -24,299 +24,312 @@ using System.Collections.Generic;
|
|||
using System.Threading;
|
||||
using Server.Guilds;
|
||||
|
||||
namespace Server {
|
||||
public sealed class ParallelSaveStrategy : SaveStrategy {
|
||||
public override string Name => "Parallel";
|
||||
namespace Server
|
||||
{
|
||||
public sealed class ParallelSaveStrategy : SaveStrategy
|
||||
{
|
||||
private Queue<Item> _decayQueue;
|
||||
|
||||
private int processorCount;
|
||||
private Consumer[] consumers;
|
||||
private int cycle;
|
||||
|
||||
public ParallelSaveStrategy( int processorCount ) {
|
||||
this.processorCount = processorCount;
|
||||
private bool finished;
|
||||
private SequentialFileWriter guildData, guildIndex;
|
||||
|
||||
_decayQueue = new Queue<Item>();
|
||||
}
|
||||
private SequentialFileWriter itemData, itemIndex;
|
||||
|
||||
private int GetThreadCount() {
|
||||
return processorCount - 1;
|
||||
}
|
||||
private SaveMetrics metrics;
|
||||
private SequentialFileWriter mobileData, mobileIndex;
|
||||
|
||||
private SaveMetrics metrics;
|
||||
private int processorCount;
|
||||
|
||||
private SequentialFileWriter itemData, itemIndex;
|
||||
private SequentialFileWriter mobileData, mobileIndex;
|
||||
private SequentialFileWriter guildData, guildIndex;
|
||||
public ParallelSaveStrategy(int processorCount)
|
||||
{
|
||||
this.processorCount = processorCount;
|
||||
|
||||
private Queue<Item> _decayQueue;
|
||||
_decayQueue = new Queue<Item>();
|
||||
}
|
||||
|
||||
private Consumer[] consumers;
|
||||
private int cycle;
|
||||
public override string Name => "Parallel";
|
||||
|
||||
private bool finished;
|
||||
private int GetThreadCount()
|
||||
{
|
||||
return processorCount - 1;
|
||||
}
|
||||
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
this.metrics = metrics;
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
this.metrics = metrics;
|
||||
|
||||
OpenFiles();
|
||||
OpenFiles();
|
||||
|
||||
consumers = new Consumer[GetThreadCount()];
|
||||
consumers = new Consumer[GetThreadCount()];
|
||||
|
||||
for ( int i = 0; i < consumers.Length; ++i ) {
|
||||
consumers[i] = new Consumer( this, 256 );
|
||||
}
|
||||
for (int i = 0; i < consumers.Length; ++i) consumers[i] = new Consumer(this, 256);
|
||||
|
||||
IEnumerable<ISerializable> collection = new Producer();
|
||||
IEnumerable<ISerializable> collection = new Producer();
|
||||
|
||||
foreach ( ISerializable value in collection ) {
|
||||
while ( !Enqueue( value ) ) {
|
||||
if ( !Commit() ) {
|
||||
Thread.Sleep( 0 );
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (ISerializable value in collection)
|
||||
while (!Enqueue(value))
|
||||
if (!Commit())
|
||||
Thread.Sleep(0);
|
||||
|
||||
finished = true;
|
||||
finished = true;
|
||||
|
||||
SaveTypeDatabases();
|
||||
SaveTypeDatabases();
|
||||
|
||||
WaitHandle.WaitAll(
|
||||
Array.ConvertAll<Consumer, WaitHandle>(
|
||||
consumers,
|
||||
delegate( Consumer input ) {
|
||||
return input.completionEvent;
|
||||
}
|
||||
)
|
||||
);
|
||||
WaitHandle.WaitAll(
|
||||
Array.ConvertAll<Consumer, WaitHandle>(
|
||||
consumers,
|
||||
delegate(Consumer input) { return input.completionEvent; }
|
||||
)
|
||||
);
|
||||
|
||||
Commit();
|
||||
Commit();
|
||||
|
||||
CloseFiles();
|
||||
}
|
||||
CloseFiles();
|
||||
}
|
||||
|
||||
public override void ProcessDecay() {
|
||||
while ( _decayQueue.Count > 0 ) {
|
||||
Item item = _decayQueue.Dequeue();
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
while (_decayQueue.Count > 0)
|
||||
{
|
||||
Item item = _decayQueue.Dequeue();
|
||||
|
||||
if ( item.OnDecay() ) {
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.OnDecay()) item.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveTypeDatabases() {
|
||||
SaveTypeDatabase( World.ItemTypesPath, World.m_ItemTypes );
|
||||
SaveTypeDatabase( World.MobileTypesPath, World.m_MobileTypes );
|
||||
}
|
||||
private void SaveTypeDatabases()
|
||||
{
|
||||
SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes);
|
||||
SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes);
|
||||
}
|
||||
|
||||
private void SaveTypeDatabase( string path, List<Type> types ) {
|
||||
BinaryFileWriter bfw = new BinaryFileWriter( path, false );
|
||||
private void SaveTypeDatabase(string path, List<Type> types)
|
||||
{
|
||||
BinaryFileWriter bfw = new BinaryFileWriter(path, false);
|
||||
|
||||
bfw.Write( types.Count );
|
||||
bfw.Write(types.Count);
|
||||
|
||||
foreach ( Type type in types ) {
|
||||
bfw.Write( type.FullName );
|
||||
}
|
||||
foreach (Type type in types) bfw.Write(type.FullName);
|
||||
|
||||
bfw.Flush();
|
||||
bfw.Flush();
|
||||
|
||||
bfw.Close();
|
||||
}
|
||||
bfw.Close();
|
||||
}
|
||||
|
||||
private void OpenFiles() {
|
||||
itemData = new SequentialFileWriter( World.ItemDataPath, metrics );
|
||||
itemIndex = new SequentialFileWriter( World.ItemIndexPath, metrics );
|
||||
private void OpenFiles()
|
||||
{
|
||||
itemData = new SequentialFileWriter(World.ItemDataPath, metrics);
|
||||
itemIndex = new SequentialFileWriter(World.ItemIndexPath, metrics);
|
||||
|
||||
mobileData = new SequentialFileWriter( World.MobileDataPath, metrics );
|
||||
mobileIndex = new SequentialFileWriter( World.MobileIndexPath, metrics );
|
||||
mobileData = new SequentialFileWriter(World.MobileDataPath, metrics);
|
||||
mobileIndex = new SequentialFileWriter(World.MobileIndexPath, metrics);
|
||||
|
||||
guildData = new SequentialFileWriter( World.GuildDataPath, metrics );
|
||||
guildIndex = new SequentialFileWriter( World.GuildIndexPath, metrics );
|
||||
guildData = new SequentialFileWriter(World.GuildDataPath, metrics);
|
||||
guildIndex = new SequentialFileWriter(World.GuildIndexPath, metrics);
|
||||
|
||||
WriteCount( itemIndex, World.Items.Count );
|
||||
WriteCount( mobileIndex, World.Mobiles.Count );
|
||||
WriteCount( guildIndex, BaseGuild.List.Count );
|
||||
}
|
||||
WriteCount(itemIndex, World.Items.Count);
|
||||
WriteCount(mobileIndex, World.Mobiles.Count);
|
||||
WriteCount(guildIndex, BaseGuild.List.Count);
|
||||
}
|
||||
|
||||
private void WriteCount( SequentialFileWriter indexFile, int count ) {
|
||||
byte[] buffer = new byte[4];
|
||||
private void WriteCount(SequentialFileWriter indexFile, int count)
|
||||
{
|
||||
byte[] buffer = new byte[4];
|
||||
|
||||
buffer[0] = ( byte ) ( count );
|
||||
buffer[1] = ( byte ) ( count >> 8 );
|
||||
buffer[2] = ( byte ) ( count >> 16 );
|
||||
buffer[3] = ( byte ) ( count >> 24 );
|
||||
buffer[0] = (byte)count;
|
||||
buffer[1] = (byte)(count >> 8);
|
||||
buffer[2] = (byte)(count >> 16);
|
||||
buffer[3] = (byte)(count >> 24);
|
||||
|
||||
indexFile.Write( buffer, 0, buffer.Length );
|
||||
}
|
||||
indexFile.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private void CloseFiles() {
|
||||
itemData.Close();
|
||||
itemIndex.Close();
|
||||
private void CloseFiles()
|
||||
{
|
||||
itemData.Close();
|
||||
itemIndex.Close();
|
||||
|
||||
mobileData.Close();
|
||||
mobileIndex.Close();
|
||||
mobileData.Close();
|
||||
mobileIndex.Close();
|
||||
|
||||
guildData.Close();
|
||||
guildIndex.Close();
|
||||
guildData.Close();
|
||||
guildIndex.Close();
|
||||
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
|
||||
private void OnSerialized( ConsumableEntry entry ) {
|
||||
ISerializable value = entry.value;
|
||||
BinaryMemoryWriter writer = entry.writer;
|
||||
private void OnSerialized(ConsumableEntry entry)
|
||||
{
|
||||
ISerializable value = entry.value;
|
||||
BinaryMemoryWriter writer = entry.writer;
|
||||
|
||||
if ( value is Item item )
|
||||
Save( item, writer );
|
||||
else if ( value is Mobile mob )
|
||||
Save( mob, writer );
|
||||
else if ( value is BaseGuild guild )
|
||||
Save( guild, writer );
|
||||
}
|
||||
if (value is Item item)
|
||||
Save(item, writer);
|
||||
else if (value is Mobile mob)
|
||||
Save(mob, writer);
|
||||
else if (value is BaseGuild guild)
|
||||
Save(guild, writer);
|
||||
}
|
||||
|
||||
private void Save( Item item, BinaryMemoryWriter writer ) {
|
||||
int length = writer.CommitTo( itemData, itemIndex, item.m_TypeRef, item.Serial );
|
||||
private void Save(Item item, BinaryMemoryWriter writer)
|
||||
{
|
||||
int length = writer.CommitTo(itemData, itemIndex, item.m_TypeRef, item.Serial);
|
||||
|
||||
metrics?.OnItemSaved( length );
|
||||
metrics?.OnItemSaved(length);
|
||||
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal && DateTime.UtcNow > (item.LastMoved + item.DecayTime))
|
||||
{
|
||||
_decayQueue.Enqueue( item );
|
||||
}
|
||||
}
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal &&
|
||||
DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
private void Save( Mobile mob, BinaryMemoryWriter writer ) {
|
||||
int length = writer.CommitTo( mobileData, mobileIndex, mob.m_TypeRef, mob.Serial );
|
||||
private void Save(Mobile mob, BinaryMemoryWriter writer)
|
||||
{
|
||||
int length = writer.CommitTo(mobileData, mobileIndex, mob.m_TypeRef, mob.Serial);
|
||||
|
||||
metrics?.OnMobileSaved( length );
|
||||
}
|
||||
metrics?.OnMobileSaved(length);
|
||||
}
|
||||
|
||||
private void Save( BaseGuild guild, BinaryMemoryWriter writer ) {
|
||||
int length = writer.CommitTo( guildData, guildIndex, 0, guild.Id );
|
||||
private void Save(BaseGuild guild, BinaryMemoryWriter writer)
|
||||
{
|
||||
int length = writer.CommitTo(guildData, guildIndex, 0, guild.Id);
|
||||
|
||||
metrics?.OnGuildSaved( length );
|
||||
}
|
||||
metrics?.OnGuildSaved(length);
|
||||
}
|
||||
|
||||
private bool Enqueue( ISerializable value ) {
|
||||
for ( int i = 0; i < consumers.Length; ++i ) {
|
||||
Consumer consumer = consumers[cycle++ % consumers.Length];
|
||||
private bool Enqueue(ISerializable value)
|
||||
{
|
||||
for (int i = 0; i < consumers.Length; ++i)
|
||||
{
|
||||
Consumer consumer = consumers[cycle++ % consumers.Length];
|
||||
|
||||
if ( ( consumer.tail - consumer.head ) < consumer.buffer.Length ) {
|
||||
consumer.buffer[consumer.tail % consumer.buffer.Length].value = value;
|
||||
consumer.tail++;
|
||||
if (consumer.tail - consumer.head < consumer.buffer.Length)
|
||||
{
|
||||
consumer.buffer[consumer.tail % consumer.buffer.Length].value = value;
|
||||
consumer.tail++;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Commit() {
|
||||
bool committed = false;
|
||||
private bool Commit()
|
||||
{
|
||||
bool committed = false;
|
||||
|
||||
for (int i = 0; i < consumers.Length; ++i)
|
||||
{
|
||||
Consumer consumer = consumers[i];
|
||||
|
||||
for ( int i = 0; i < consumers.Length; ++i ) {
|
||||
Consumer consumer = consumers[i];
|
||||
while (consumer.head < consumer.done)
|
||||
{
|
||||
OnSerialized(consumer.buffer[consumer.head % consumer.buffer.Length]);
|
||||
consumer.head++;
|
||||
|
||||
while ( consumer.head < consumer.done ) {
|
||||
OnSerialized( consumer.buffer[consumer.head % consumer.buffer.Length] );
|
||||
consumer.head++;
|
||||
committed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return committed;
|
||||
}
|
||||
|
||||
private sealed class Producer : IEnumerable<ISerializable>
|
||||
{
|
||||
private IEnumerable<BaseGuild> guilds;
|
||||
private IEnumerable<Item> items;
|
||||
private IEnumerable<Mobile> mobiles;
|
||||
|
||||
public Producer()
|
||||
{
|
||||
items = World.Items.Values;
|
||||
mobiles = World.Mobiles.Values;
|
||||
guilds = BaseGuild.List.Values;
|
||||
}
|
||||
|
||||
public IEnumerator<ISerializable> GetEnumerator()
|
||||
{
|
||||
foreach (Item item in items) yield return item;
|
||||
|
||||
foreach (Mobile mob in mobiles) yield return mob;
|
||||
|
||||
committed = true;
|
||||
}
|
||||
}
|
||||
foreach (BaseGuild guild in guilds) yield return guild;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private struct ConsumableEntry
|
||||
{
|
||||
public ISerializable value;
|
||||
public BinaryMemoryWriter writer;
|
||||
}
|
||||
|
||||
private sealed class Consumer
|
||||
{
|
||||
public ConsumableEntry[] buffer;
|
||||
|
||||
return committed;
|
||||
}
|
||||
public ManualResetEvent completionEvent;
|
||||
public int head, done, tail;
|
||||
private ParallelSaveStrategy owner;
|
||||
|
||||
private sealed class Producer : IEnumerable<ISerializable> {
|
||||
private IEnumerable<Item> items;
|
||||
private IEnumerable<Mobile> mobiles;
|
||||
private IEnumerable<BaseGuild> guilds;
|
||||
private Thread thread;
|
||||
|
||||
public Producer() {
|
||||
items = World.Items.Values;
|
||||
mobiles = World.Mobiles.Values;
|
||||
guilds = BaseGuild.List.Values;
|
||||
}
|
||||
public Consumer(ParallelSaveStrategy owner, int bufferSize)
|
||||
{
|
||||
this.owner = owner;
|
||||
|
||||
public IEnumerator<ISerializable> GetEnumerator() {
|
||||
foreach ( Item item in items ) {
|
||||
yield return item;
|
||||
}
|
||||
buffer = new ConsumableEntry[bufferSize];
|
||||
|
||||
for (int i = 0; i < buffer.Length; ++i) buffer[i].writer = new BinaryMemoryWriter();
|
||||
|
||||
foreach ( Mobile mob in mobiles ) {
|
||||
yield return mob;
|
||||
}
|
||||
completionEvent = new ManualResetEvent(false);
|
||||
|
||||
thread = new Thread(Processor);
|
||||
|
||||
thread.Name = "Parallel Serialization Thread";
|
||||
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void Processor()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!owner.finished)
|
||||
{
|
||||
Process();
|
||||
Thread.Sleep(0);
|
||||
}
|
||||
|
||||
foreach ( BaseGuild guild in guilds ) {
|
||||
yield return guild;
|
||||
}
|
||||
}
|
||||
Process();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator() {
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
completionEvent.Set();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void Process()
|
||||
{
|
||||
ConsumableEntry entry;
|
||||
|
||||
while (done < tail)
|
||||
{
|
||||
entry = buffer[done % buffer.Length];
|
||||
|
||||
entry.value.Serialize(entry.writer);
|
||||
|
||||
private struct ConsumableEntry {
|
||||
public ISerializable value;
|
||||
public BinaryMemoryWriter writer;
|
||||
}
|
||||
|
||||
private sealed class Consumer {
|
||||
private ParallelSaveStrategy owner;
|
||||
|
||||
public ManualResetEvent completionEvent;
|
||||
|
||||
public ConsumableEntry[] buffer;
|
||||
public int head, done, tail;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
public Consumer( ParallelSaveStrategy owner, int bufferSize ) {
|
||||
this.owner = owner;
|
||||
|
||||
buffer = new ConsumableEntry[bufferSize];
|
||||
|
||||
for ( int i = 0; i < buffer.Length; ++i ) {
|
||||
buffer[i].writer = new BinaryMemoryWriter();
|
||||
}
|
||||
|
||||
completionEvent = new ManualResetEvent( false );
|
||||
|
||||
thread = new Thread( Processor );
|
||||
|
||||
thread.Name = "Parallel Serialization Thread";
|
||||
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void Processor() {
|
||||
try {
|
||||
while ( !owner.finished ) {
|
||||
Process();
|
||||
Thread.Sleep( 0 );
|
||||
}
|
||||
|
||||
Process();
|
||||
|
||||
completionEvent.Set();
|
||||
} catch ( Exception ex ) {
|
||||
Console.WriteLine( ex );
|
||||
}
|
||||
}
|
||||
|
||||
private void Process() {
|
||||
ConsumableEntry entry;
|
||||
|
||||
while ( done < tail ) {
|
||||
entry = buffer[done % buffer.Length];
|
||||
|
||||
entry.value.Serialize( entry.writer );
|
||||
|
||||
++done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
++done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,117 +1,105 @@
|
|||
#region References
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Persistence
|
||||
{
|
||||
public static void Serialize(string path, Action<GenericWriter> serializer)
|
||||
{
|
||||
Serialize(new FileInfo(path), serializer);
|
||||
}
|
||||
public static class Persistence
|
||||
{
|
||||
public static void Serialize(string path, Action<GenericWriter> serializer)
|
||||
{
|
||||
Serialize(new FileInfo(path), serializer);
|
||||
}
|
||||
|
||||
public static void Serialize(FileInfo file, Action<GenericWriter> serializer)
|
||||
{
|
||||
file.Refresh();
|
||||
public static void Serialize(FileInfo file, Action<GenericWriter> serializer)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Directory != null && !file.Directory.Exists)
|
||||
{
|
||||
file.Directory.Create();
|
||||
}
|
||||
if (file.Directory != null && !file.Directory.Exists) file.Directory.Create();
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
file.Create().Close();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
if (!file.Exists) file.Create().Close();
|
||||
|
||||
using (var fs = file.OpenWrite())
|
||||
{
|
||||
var writer = new BinaryFileWriter(fs, true);
|
||||
file.Refresh();
|
||||
|
||||
try
|
||||
{
|
||||
serializer(writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
using (FileStream fs = file.OpenWrite())
|
||||
{
|
||||
BinaryFileWriter writer = new BinaryFileWriter(fs, true);
|
||||
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(path, deserializer, true);
|
||||
}
|
||||
try
|
||||
{
|
||||
serializer(writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(file, deserializer, true);
|
||||
}
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(path, deserializer, true);
|
||||
}
|
||||
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
Deserialize(new FileInfo(path), deserializer, ensure);
|
||||
}
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(file, deserializer, true);
|
||||
}
|
||||
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
file.Refresh();
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
Deserialize(new FileInfo(path), deserializer, ensure);
|
||||
}
|
||||
|
||||
if (file.Directory != null && !file.Directory.Exists)
|
||||
{
|
||||
if (!ensure)
|
||||
{
|
||||
throw new DirectoryNotFoundException();
|
||||
}
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
file.Directory.Create();
|
||||
}
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
if (!ensure)
|
||||
{
|
||||
throw new FileNotFoundException
|
||||
{
|
||||
Source = file.FullName
|
||||
};
|
||||
}
|
||||
if (file.Directory != null && !file.Directory.Exists)
|
||||
{
|
||||
if (!ensure) throw new DirectoryNotFoundException();
|
||||
|
||||
file.Create().Close();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
file.Directory.Create();
|
||||
}
|
||||
|
||||
using (var fs = file.OpenRead())
|
||||
{
|
||||
var reader = new BinaryFileReader(new BinaryReader(fs));
|
||||
if (!file.Exists)
|
||||
{
|
||||
if (!ensure)
|
||||
throw new FileNotFoundException
|
||||
{
|
||||
Source = file.FullName
|
||||
};
|
||||
|
||||
try
|
||||
{
|
||||
deserializer(reader);
|
||||
}
|
||||
catch (EndOfStreamException eos)
|
||||
{
|
||||
if (file.Length > 0)
|
||||
{
|
||||
Console.WriteLine("[Persistence]: {0}", eos);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("[Persistence]: {0}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
file.Create().Close();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
using (FileStream fs = file.OpenRead())
|
||||
{
|
||||
BinaryFileReader reader = new BinaryFileReader(new BinaryReader(fs));
|
||||
|
||||
try
|
||||
{
|
||||
deserializer(reader);
|
||||
}
|
||||
catch (EndOfStreamException eos)
|
||||
{
|
||||
if (file.Length > 0) Console.WriteLine("[Persistence]: {0}", eos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("[Persistence]: {0}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -18,104 +18,104 @@
|
|||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System.IO;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class QueuedMemoryWriter : BinaryFileWriter
|
||||
{
|
||||
private struct IndexInfo
|
||||
{
|
||||
public int size;
|
||||
public int typeCode;
|
||||
public int serial;
|
||||
}
|
||||
public sealed class QueuedMemoryWriter : BinaryFileWriter
|
||||
{
|
||||
private MemoryStream _memStream;
|
||||
private List<IndexInfo> _orderedIndexInfo = new List<IndexInfo>();
|
||||
|
||||
private MemoryStream _memStream;
|
||||
private List<IndexInfo> _orderedIndexInfo = new List<IndexInfo>();
|
||||
public QueuedMemoryWriter()
|
||||
: base(new MemoryStream(1024 * 1024), true)
|
||||
{
|
||||
_memStream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
|
||||
protected override int BufferSize => 512;
|
||||
protected override int BufferSize => 512;
|
||||
|
||||
public QueuedMemoryWriter()
|
||||
: base(new MemoryStream(1024 * 1024), true)
|
||||
{
|
||||
_memStream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
public void QueueForIndex(ISerializable serializable, int size)
|
||||
{
|
||||
IndexInfo info;
|
||||
|
||||
public void QueueForIndex(ISerializable serializable, int size)
|
||||
{
|
||||
IndexInfo info;
|
||||
info.size = size;
|
||||
|
||||
info.size = size;
|
||||
info.typeCode = serializable.TypeReference; //For guilds, this will automagically be zero.
|
||||
info.serial = serializable.SerialIdentity;
|
||||
|
||||
info.typeCode = serializable.TypeReference; //For guilds, this will automagically be zero.
|
||||
info.serial = serializable.SerialIdentity;
|
||||
_orderedIndexInfo.Add(info);
|
||||
}
|
||||
|
||||
_orderedIndexInfo.Add(info);
|
||||
}
|
||||
public void CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile)
|
||||
{
|
||||
Flush();
|
||||
|
||||
public void CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile)
|
||||
{
|
||||
Flush();
|
||||
int memLength = (int)_memStream.Position;
|
||||
|
||||
int memLength = (int)_memStream.Position;
|
||||
if (memLength > 0)
|
||||
{
|
||||
byte[] memBuffer = _memStream.GetBuffer();
|
||||
|
||||
if (memLength > 0)
|
||||
{
|
||||
byte[] memBuffer = _memStream.GetBuffer();
|
||||
long actualPosition = dataFile.Position;
|
||||
|
||||
long actualPosition = dataFile.Position;
|
||||
dataFile.Write(memBuffer, 0, memLength); //The buffer contains the data from many items.
|
||||
|
||||
dataFile.Write(memBuffer, 0, memLength); //The buffer contains the data from many items.
|
||||
//Console.WriteLine("Writing {0} bytes starting at {1}, with {2} things", memLength, actualPosition, _orderedIndexInfo.Count);
|
||||
|
||||
//Console.WriteLine("Writing {0} bytes starting at {1}, with {2} things", memLength, actualPosition, _orderedIndexInfo.Count);
|
||||
byte[] indexBuffer = new byte[20];
|
||||
|
||||
byte[] indexBuffer = new byte[20];
|
||||
//int indexWritten = _orderedIndexInfo.Count * indexBuffer.Length;
|
||||
//int totalWritten = memLength + indexWritten
|
||||
|
||||
//int indexWritten = _orderedIndexInfo.Count * indexBuffer.Length;
|
||||
//int totalWritten = memLength + indexWritten
|
||||
for (int i = 0; i < _orderedIndexInfo.Count; i++)
|
||||
{
|
||||
IndexInfo info = _orderedIndexInfo[i];
|
||||
|
||||
for (int i = 0; i < _orderedIndexInfo.Count; i++)
|
||||
{
|
||||
IndexInfo info = _orderedIndexInfo[i];
|
||||
|
||||
int typeCode = info.typeCode;
|
||||
int serial = info.serial;
|
||||
int length = info.size;
|
||||
int typeCode = info.typeCode;
|
||||
int serial = info.serial;
|
||||
int length = info.size;
|
||||
|
||||
|
||||
indexBuffer[0] = (byte)(info.typeCode);
|
||||
indexBuffer[1] = (byte)(info.typeCode >> 8);
|
||||
indexBuffer[2] = (byte)(info.typeCode >> 16);
|
||||
indexBuffer[3] = (byte)(info.typeCode >> 24);
|
||||
indexBuffer[0] = (byte)info.typeCode;
|
||||
indexBuffer[1] = (byte)(info.typeCode >> 8);
|
||||
indexBuffer[2] = (byte)(info.typeCode >> 16);
|
||||
indexBuffer[3] = (byte)(info.typeCode >> 24);
|
||||
|
||||
indexBuffer[4] = (byte)(info.serial);
|
||||
indexBuffer[5] = (byte)(info.serial >> 8);
|
||||
indexBuffer[6] = (byte)(info.serial >> 16);
|
||||
indexBuffer[7] = (byte)(info.serial >> 24);
|
||||
indexBuffer[4] = (byte)info.serial;
|
||||
indexBuffer[5] = (byte)(info.serial >> 8);
|
||||
indexBuffer[6] = (byte)(info.serial >> 16);
|
||||
indexBuffer[7] = (byte)(info.serial >> 24);
|
||||
|
||||
indexBuffer[8] = (byte)(actualPosition);
|
||||
indexBuffer[9] = (byte)(actualPosition >> 8);
|
||||
indexBuffer[10] = (byte)(actualPosition >> 16);
|
||||
indexBuffer[11] = (byte)(actualPosition >> 24);
|
||||
indexBuffer[12] = (byte)(actualPosition >> 32);
|
||||
indexBuffer[13] = (byte)(actualPosition >> 40);
|
||||
indexBuffer[14] = (byte)(actualPosition >> 48);
|
||||
indexBuffer[15] = (byte)(actualPosition >> 56);
|
||||
indexBuffer[8] = (byte)actualPosition;
|
||||
indexBuffer[9] = (byte)(actualPosition >> 8);
|
||||
indexBuffer[10] = (byte)(actualPosition >> 16);
|
||||
indexBuffer[11] = (byte)(actualPosition >> 24);
|
||||
indexBuffer[12] = (byte)(actualPosition >> 32);
|
||||
indexBuffer[13] = (byte)(actualPosition >> 40);
|
||||
indexBuffer[14] = (byte)(actualPosition >> 48);
|
||||
indexBuffer[15] = (byte)(actualPosition >> 56);
|
||||
|
||||
indexBuffer[16] = (byte)(info.size);
|
||||
indexBuffer[17] = (byte)(info.size >> 8);
|
||||
indexBuffer[18] = (byte)(info.size >> 16);
|
||||
indexBuffer[19] = (byte)(info.size >> 24);
|
||||
indexBuffer[16] = (byte)info.size;
|
||||
indexBuffer[17] = (byte)(info.size >> 8);
|
||||
indexBuffer[18] = (byte)(info.size >> 16);
|
||||
indexBuffer[19] = (byte)(info.size >> 24);
|
||||
|
||||
indexFile.Write(indexBuffer, 0, indexBuffer.Length);
|
||||
indexFile.Write(indexBuffer, 0, indexBuffer.Length);
|
||||
|
||||
actualPosition += info.size;
|
||||
}
|
||||
}
|
||||
actualPosition += info.size;
|
||||
}
|
||||
}
|
||||
|
||||
Close(); //We're done with this writer.
|
||||
}
|
||||
}
|
||||
Close(); //We're done with this writer.
|
||||
}
|
||||
|
||||
private struct IndexInfo
|
||||
{
|
||||
public int size;
|
||||
public int typeCode;
|
||||
public int serial;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,109 +21,120 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace Server {
|
||||
public sealed class SaveMetrics : IDisposable {
|
||||
private const string PerformanceCategoryName = "RunUO 2.1";
|
||||
private const string PerformanceCategoryDesc = "Performance counters for RunUO 2.1.";
|
||||
namespace Server
|
||||
{
|
||||
public sealed class SaveMetrics : IDisposable
|
||||
{
|
||||
private const string PerformanceCategoryName = "RunUO 2.1";
|
||||
private const string PerformanceCategoryDesc = "Performance counters for RunUO 2.1.";
|
||||
|
||||
private PerformanceCounter numberOfWorldSaves;
|
||||
private bool isDisposed;
|
||||
|
||||
private PerformanceCounter itemsPerSecond;
|
||||
private PerformanceCounter mobilesPerSecond;
|
||||
private PerformanceCounter itemsPerSecond;
|
||||
private PerformanceCounter mobilesPerSecond;
|
||||
|
||||
private PerformanceCounter serializedBytesPerSecond;
|
||||
private PerformanceCounter writtenBytesPerSecond;
|
||||
private PerformanceCounter numberOfWorldSaves;
|
||||
|
||||
public SaveMetrics() {
|
||||
if ( !PerformanceCounterCategory.Exists( PerformanceCategoryName ) ) {
|
||||
CounterCreationDataCollection counters = new CounterCreationDataCollection();
|
||||
private PerformanceCounter serializedBytesPerSecond;
|
||||
private PerformanceCounter writtenBytesPerSecond;
|
||||
|
||||
counters.Add( new CounterCreationData(
|
||||
"Save - Count",
|
||||
"Number of world saves.",
|
||||
PerformanceCounterType.NumberOfItems32
|
||||
)
|
||||
);
|
||||
public SaveMetrics()
|
||||
{
|
||||
if (!PerformanceCounterCategory.Exists(PerformanceCategoryName))
|
||||
{
|
||||
CounterCreationDataCollection counters = new CounterCreationDataCollection();
|
||||
|
||||
counters.Add( new CounterCreationData(
|
||||
"Save - Items/sec",
|
||||
"Number of items saved per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
counters.Add(new CounterCreationData(
|
||||
"Save - Count",
|
||||
"Number of world saves.",
|
||||
PerformanceCounterType.NumberOfItems32
|
||||
)
|
||||
);
|
||||
|
||||
counters.Add( new CounterCreationData(
|
||||
"Save - Mobiles/sec",
|
||||
"Number of mobiles saved per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
counters.Add(new CounterCreationData(
|
||||
"Save - Items/sec",
|
||||
"Number of items saved per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
|
||||
counters.Add( new CounterCreationData(
|
||||
"Save - Serialized bytes/sec",
|
||||
"Amount of world-save bytes serialized per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
counters.Add(new CounterCreationData(
|
||||
"Save - Mobiles/sec",
|
||||
"Number of mobiles saved per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
|
||||
counters.Add( new CounterCreationData(
|
||||
"Save - Written bytes/sec",
|
||||
"Amount of world-save bytes written to disk per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
counters.Add(new CounterCreationData(
|
||||
"Save - Serialized bytes/sec",
|
||||
"Amount of world-save bytes serialized per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
|
||||
counters.Add(new CounterCreationData(
|
||||
"Save - Written bytes/sec",
|
||||
"Amount of world-save bytes written to disk per second.",
|
||||
PerformanceCounterType.RateOfCountsPerSecond32
|
||||
)
|
||||
);
|
||||
|
||||
#if !MONO
|
||||
PerformanceCounterCategory.Create( PerformanceCategoryName, PerformanceCategoryDesc, PerformanceCounterCategoryType.SingleInstance, counters );
|
||||
PerformanceCounterCategory.Create(PerformanceCategoryName, PerformanceCategoryDesc,
|
||||
PerformanceCounterCategoryType.SingleInstance, counters);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
numberOfWorldSaves = new PerformanceCounter( PerformanceCategoryName, "Save - Count", false );
|
||||
numberOfWorldSaves = new PerformanceCounter(PerformanceCategoryName, "Save - Count", false);
|
||||
|
||||
itemsPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Items/sec", false );
|
||||
mobilesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Mobiles/sec", false );
|
||||
itemsPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Items/sec", false);
|
||||
mobilesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Mobiles/sec", false);
|
||||
|
||||
serializedBytesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Serialized bytes/sec", false );
|
||||
writtenBytesPerSecond = new PerformanceCounter( PerformanceCategoryName, "Save - Written bytes/sec", false );
|
||||
serializedBytesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Serialized bytes/sec", false);
|
||||
writtenBytesPerSecond = new PerformanceCounter(PerformanceCategoryName, "Save - Written bytes/sec", false);
|
||||
|
||||
// increment number of world saves
|
||||
numberOfWorldSaves.Increment();
|
||||
}
|
||||
// increment number of world saves
|
||||
numberOfWorldSaves.Increment();
|
||||
}
|
||||
|
||||
public void OnItemSaved( int numberOfBytes ) {
|
||||
itemsPerSecond.Increment();
|
||||
public void Dispose()
|
||||
{
|
||||
if (!isDisposed)
|
||||
{
|
||||
isDisposed = true;
|
||||
|
||||
serializedBytesPerSecond.IncrementBy( numberOfBytes );
|
||||
}
|
||||
numberOfWorldSaves.Dispose();
|
||||
|
||||
public void OnMobileSaved( int numberOfBytes ) {
|
||||
mobilesPerSecond.Increment();
|
||||
itemsPerSecond.Dispose();
|
||||
mobilesPerSecond.Dispose();
|
||||
|
||||
serializedBytesPerSecond.IncrementBy( numberOfBytes );
|
||||
}
|
||||
serializedBytesPerSecond.Dispose();
|
||||
writtenBytesPerSecond.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnGuildSaved( int numberOfBytes ) {
|
||||
serializedBytesPerSecond.IncrementBy( numberOfBytes );
|
||||
}
|
||||
public void OnItemSaved(int numberOfBytes)
|
||||
{
|
||||
itemsPerSecond.Increment();
|
||||
|
||||
public void OnFileWritten( int numberOfBytes ) {
|
||||
writtenBytesPerSecond.IncrementBy( numberOfBytes );
|
||||
}
|
||||
serializedBytesPerSecond.IncrementBy(numberOfBytes);
|
||||
}
|
||||
|
||||
private bool isDisposed;
|
||||
public void OnMobileSaved(int numberOfBytes)
|
||||
{
|
||||
mobilesPerSecond.Increment();
|
||||
|
||||
public void Dispose() {
|
||||
if ( !isDisposed ) {
|
||||
isDisposed = true;
|
||||
serializedBytesPerSecond.IncrementBy(numberOfBytes);
|
||||
}
|
||||
|
||||
numberOfWorldSaves.Dispose();
|
||||
public void OnGuildSaved(int numberOfBytes)
|
||||
{
|
||||
serializedBytesPerSecond.IncrementBy(numberOfBytes);
|
||||
}
|
||||
|
||||
itemsPerSecond.Dispose();
|
||||
mobilesPerSecond.Dispose();
|
||||
|
||||
serializedBytesPerSecond.Dispose();
|
||||
writtenBytesPerSecond.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public void OnFileWritten(int numberOfBytes)
|
||||
{
|
||||
writtenBytesPerSecond.IncrementBy(numberOfBytes);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,28 +20,28 @@
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class SaveStrategy
|
||||
{
|
||||
public static SaveStrategy Acquire()
|
||||
{
|
||||
if (Core.MultiProcessor)
|
||||
{
|
||||
int processorCount = Core.ProcessorCount;
|
||||
public abstract class SaveStrategy
|
||||
{
|
||||
public abstract string Name{ get; }
|
||||
|
||||
if (processorCount > 2)
|
||||
{
|
||||
return new DualSaveStrategy(); // return new DynamicSaveStrategy(); (4.0 or return new ParallelSaveStrategy(processorCount); (2.0)
|
||||
}
|
||||
public static SaveStrategy Acquire()
|
||||
{
|
||||
if (Core.MultiProcessor)
|
||||
{
|
||||
int processorCount = Core.ProcessorCount;
|
||||
|
||||
return new DualSaveStrategy();
|
||||
}
|
||||
if (processorCount > 2)
|
||||
return
|
||||
new DualSaveStrategy(); // return new DynamicSaveStrategy(); (4.0 or return new ParallelSaveStrategy(processorCount); (2.0)
|
||||
|
||||
return new StandardSaveStrategy();
|
||||
}
|
||||
return new DualSaveStrategy();
|
||||
}
|
||||
|
||||
public abstract string Name { get; }
|
||||
public abstract void Save(SaveMetrics metrics, bool permitBackgroundWrite);
|
||||
return new StandardSaveStrategy();
|
||||
}
|
||||
|
||||
public abstract void ProcessDecay();
|
||||
}
|
||||
public abstract void Save(SaveMetrics metrics, bool permitBackgroundWrite);
|
||||
|
||||
public abstract void ProcessDecay();
|
||||
}
|
||||
}
|
||||
|
|
@ -21,102 +21,114 @@
|
|||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Server {
|
||||
public sealed class SequentialFileWriter : Stream {
|
||||
private FileStream fileStream;
|
||||
private FileQueue fileQueue;
|
||||
namespace Server
|
||||
{
|
||||
public sealed class SequentialFileWriter : Stream
|
||||
{
|
||||
private FileQueue fileQueue;
|
||||
private FileStream fileStream;
|
||||
|
||||
private AsyncCallback writeCallback;
|
||||
private SaveMetrics metrics;
|
||||
|
||||
private SaveMetrics metrics;
|
||||
private AsyncCallback writeCallback;
|
||||
|
||||
public SequentialFileWriter( string path, SaveMetrics metrics ) {
|
||||
if ( path == null ) {
|
||||
throw new ArgumentNullException( "path" );
|
||||
}
|
||||
public SequentialFileWriter(string path, SaveMetrics metrics)
|
||||
{
|
||||
if (path == null) throw new ArgumentNullException("path");
|
||||
|
||||
this.metrics = metrics;
|
||||
this.metrics = metrics;
|
||||
|
||||
fileStream = FileOperations.OpenSequentialStream( path, FileMode.Create, FileAccess.Write, FileShare.None );
|
||||
fileStream = FileOperations.OpenSequentialStream(path, FileMode.Create, FileAccess.Write, FileShare.None);
|
||||
|
||||
fileQueue = new FileQueue(
|
||||
Math.Max( 1, FileOperations.Concurrency ),
|
||||
FileCallback
|
||||
);
|
||||
}
|
||||
fileQueue = new FileQueue(
|
||||
Math.Max(1, FileOperations.Concurrency),
|
||||
FileCallback
|
||||
);
|
||||
}
|
||||
|
||||
public override long Position {
|
||||
get => fileQueue.Position;
|
||||
set => throw new InvalidOperationException();
|
||||
}
|
||||
public override long Position
|
||||
{
|
||||
get => fileQueue.Position;
|
||||
set => throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
private void FileCallback( FileQueue.Chunk chunk ) {
|
||||
if ( FileOperations.AreSynchronous ) {
|
||||
fileStream.Write( chunk.Buffer, chunk.Offset, chunk.Size );
|
||||
public override bool CanRead => false;
|
||||
|
||||
metrics?.OnFileWritten( chunk.Size );
|
||||
public override bool CanSeek => false;
|
||||
|
||||
chunk.Commit();
|
||||
} else {
|
||||
if ( writeCallback == null ) {
|
||||
writeCallback = OnWrite;
|
||||
}
|
||||
public override bool CanWrite => true;
|
||||
|
||||
fileStream.BeginWrite( chunk.Buffer, chunk.Offset, chunk.Size, writeCallback, chunk );
|
||||
}
|
||||
}
|
||||
public override long Length => Position;
|
||||
|
||||
private void OnWrite( IAsyncResult asyncResult ) {
|
||||
FileQueue.Chunk chunk = asyncResult.AsyncState as FileQueue.Chunk;
|
||||
private void FileCallback(FileQueue.Chunk chunk)
|
||||
{
|
||||
if (FileOperations.AreSynchronous)
|
||||
{
|
||||
fileStream.Write(chunk.Buffer, chunk.Offset, chunk.Size);
|
||||
|
||||
fileStream.EndWrite( asyncResult );
|
||||
metrics?.OnFileWritten(chunk.Size);
|
||||
|
||||
metrics?.OnFileWritten( chunk.Size );
|
||||
chunk.Commit();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (writeCallback == null) writeCallback = OnWrite;
|
||||
|
||||
chunk.Commit();
|
||||
}
|
||||
fileStream.BeginWrite(chunk.Buffer, chunk.Offset, chunk.Size, writeCallback, chunk);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write( byte[] buffer, int offset, int size ) {
|
||||
fileQueue.Enqueue( buffer, offset, size );
|
||||
}
|
||||
private void OnWrite(IAsyncResult asyncResult)
|
||||
{
|
||||
FileQueue.Chunk chunk = asyncResult.AsyncState as FileQueue.Chunk;
|
||||
|
||||
public override void Flush() {
|
||||
fileQueue.Flush();
|
||||
fileStream.Flush();
|
||||
}
|
||||
fileStream.EndWrite(asyncResult);
|
||||
|
||||
protected override void Dispose( bool disposing ) {
|
||||
if ( fileStream != null ) {
|
||||
Flush();
|
||||
metrics?.OnFileWritten(chunk.Size);
|
||||
|
||||
fileQueue.Dispose();
|
||||
fileQueue = null;
|
||||
chunk.Commit();
|
||||
}
|
||||
|
||||
fileStream.Close();
|
||||
fileStream = null;
|
||||
}
|
||||
public override void Write(byte[] buffer, int offset, int size)
|
||||
{
|
||||
fileQueue.Enqueue(buffer, offset, size);
|
||||
}
|
||||
|
||||
base.Dispose( disposing );
|
||||
}
|
||||
public override void Flush()
|
||||
{
|
||||
fileQueue.Flush();
|
||||
fileStream.Flush();
|
||||
}
|
||||
|
||||
public override bool CanRead => false;
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (fileStream != null)
|
||||
{
|
||||
Flush();
|
||||
|
||||
public override bool CanSeek => false;
|
||||
fileQueue.Dispose();
|
||||
fileQueue = null;
|
||||
|
||||
public override bool CanWrite => true;
|
||||
fileStream.Close();
|
||||
fileStream = null;
|
||||
}
|
||||
|
||||
public override long Length => Position;
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
public override int Read( byte[] buffer, int offset, int count ) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
public override int Read(byte[] buffer, int offset, int count)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override long Seek( long offset, SeekOrigin origin ) {
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
public override long Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
throw new InvalidOperationException();
|
||||
}
|
||||
|
||||
public override void SetLength( long value ) {
|
||||
fileStream.SetLength( value );
|
||||
}
|
||||
}
|
||||
}
|
||||
public override void SetLength(long value)
|
||||
{
|
||||
fileStream.SetLength(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,180 +22,191 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using Server.Guilds;
|
||||
|
||||
namespace Server {
|
||||
public class StandardSaveStrategy : SaveStrategy {
|
||||
public enum SaveOption
|
||||
{
|
||||
Normal,
|
||||
Threaded
|
||||
}
|
||||
namespace Server
|
||||
{
|
||||
public class StandardSaveStrategy : SaveStrategy
|
||||
{
|
||||
public enum SaveOption
|
||||
{
|
||||
Normal,
|
||||
Threaded
|
||||
}
|
||||
|
||||
public static SaveOption SaveType = SaveOption.Normal;
|
||||
public static SaveOption SaveType = SaveOption.Normal;
|
||||
|
||||
public override string Name => "Standard";
|
||||
private Queue<Item> _decayQueue;
|
||||
|
||||
private Queue<Item> _decayQueue;
|
||||
public StandardSaveStrategy()
|
||||
{
|
||||
_decayQueue = new Queue<Item>();
|
||||
}
|
||||
|
||||
public StandardSaveStrategy() {
|
||||
_decayQueue = new Queue<Item>();
|
||||
}
|
||||
public override string Name => "Standard";
|
||||
|
||||
protected bool PermitBackgroundWrite { get; set; }
|
||||
protected bool PermitBackgroundWrite{ get; set; }
|
||||
|
||||
protected bool UseSequentialWriters => (SaveType == SaveOption.Normal || !PermitBackgroundWrite);
|
||||
protected bool UseSequentialWriters => SaveType == SaveOption.Normal || !PermitBackgroundWrite;
|
||||
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
PermitBackgroundWrite = permitBackgroundWrite;
|
||||
public override void Save(SaveMetrics metrics, bool permitBackgroundWrite)
|
||||
{
|
||||
PermitBackgroundWrite = permitBackgroundWrite;
|
||||
|
||||
SaveMobiles(metrics);
|
||||
SaveItems(metrics);
|
||||
SaveGuilds(metrics);
|
||||
SaveMobiles(metrics);
|
||||
SaveItems(metrics);
|
||||
SaveGuilds(metrics);
|
||||
|
||||
if (permitBackgroundWrite && UseSequentialWriters) //If we're permitted to write in the background, but we don't anyways, then notify.
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
if (permitBackgroundWrite && UseSequentialWriters
|
||||
) //If we're permitted to write in the background, but we don't anyways, then notify.
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
|
||||
protected void SaveMobiles(SaveMetrics metrics)
|
||||
{
|
||||
Dictionary<Serial, Mobile> mobiles = World.Mobiles;
|
||||
protected void SaveMobiles(SaveMetrics metrics)
|
||||
{
|
||||
Dictionary<Serial, Mobile> mobiles = World.Mobiles;
|
||||
|
||||
GenericWriter idx;
|
||||
GenericWriter tdb;
|
||||
GenericWriter bin;
|
||||
GenericWriter idx;
|
||||
GenericWriter tdb;
|
||||
GenericWriter bin;
|
||||
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter( World.MobileIndexPath, false );
|
||||
tdb = new BinaryFileWriter( World.MobileTypesPath, false );
|
||||
bin = new BinaryFileWriter( World.MobileDataPath, true );
|
||||
} else {
|
||||
idx = new AsyncWriter( World.MobileIndexPath, false );
|
||||
tdb = new AsyncWriter( World.MobileTypesPath, false );
|
||||
bin = new AsyncWriter( World.MobileDataPath, true );
|
||||
}
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter(World.MobileIndexPath, false);
|
||||
tdb = new BinaryFileWriter(World.MobileTypesPath, false);
|
||||
bin = new BinaryFileWriter(World.MobileDataPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = new AsyncWriter(World.MobileIndexPath, false);
|
||||
tdb = new AsyncWriter(World.MobileTypesPath, false);
|
||||
bin = new AsyncWriter(World.MobileDataPath, true);
|
||||
}
|
||||
|
||||
idx.Write( ( int ) mobiles.Count );
|
||||
foreach ( Mobile m in mobiles.Values ) {
|
||||
long start = bin.Position;
|
||||
idx.Write(mobiles.Count);
|
||||
foreach (Mobile m in mobiles.Values)
|
||||
{
|
||||
long start = bin.Position;
|
||||
|
||||
idx.Write( ( int ) m.m_TypeRef );
|
||||
idx.Write( ( int ) m.Serial );
|
||||
idx.Write( ( long ) start );
|
||||
idx.Write(m.m_TypeRef);
|
||||
idx.Write(m.Serial);
|
||||
idx.Write(start);
|
||||
|
||||
m.Serialize( bin );
|
||||
m.Serialize(bin);
|
||||
|
||||
metrics?.OnMobileSaved( ( int ) ( bin.Position - start ) );
|
||||
metrics?.OnMobileSaved((int)(bin.Position - start));
|
||||
|
||||
idx.Write( ( int ) ( bin.Position - start ) );
|
||||
idx.Write((int)(bin.Position - start));
|
||||
|
||||
m.FreeCache();
|
||||
}
|
||||
m.FreeCache();
|
||||
}
|
||||
|
||||
tdb.Write( ( int ) World.m_MobileTypes.Count );
|
||||
tdb.Write(World.m_MobileTypes.Count);
|
||||
|
||||
for ( int i = 0; i < World.m_MobileTypes.Count; ++i )
|
||||
tdb.Write( World.m_MobileTypes[i].FullName );
|
||||
for (int i = 0; i < World.m_MobileTypes.Count; ++i)
|
||||
tdb.Write(World.m_MobileTypes[i].FullName);
|
||||
|
||||
idx.Close();
|
||||
tdb.Close();
|
||||
bin.Close();
|
||||
}
|
||||
idx.Close();
|
||||
tdb.Close();
|
||||
bin.Close();
|
||||
}
|
||||
|
||||
protected void SaveItems(SaveMetrics metrics)
|
||||
{
|
||||
Dictionary<Serial, Item> items = World.Items;
|
||||
protected void SaveItems(SaveMetrics metrics)
|
||||
{
|
||||
Dictionary<Serial, Item> items = World.Items;
|
||||
|
||||
GenericWriter idx;
|
||||
GenericWriter tdb;
|
||||
GenericWriter bin;
|
||||
GenericWriter idx;
|
||||
GenericWriter tdb;
|
||||
GenericWriter bin;
|
||||
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter( World.ItemIndexPath, false );
|
||||
tdb = new BinaryFileWriter( World.ItemTypesPath, false );
|
||||
bin = new BinaryFileWriter( World.ItemDataPath, true );
|
||||
} else {
|
||||
idx = new AsyncWriter( World.ItemIndexPath, false );
|
||||
tdb = new AsyncWriter( World.ItemTypesPath, false );
|
||||
bin = new AsyncWriter( World.ItemDataPath, true );
|
||||
}
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter(World.ItemIndexPath, false);
|
||||
tdb = new BinaryFileWriter(World.ItemTypesPath, false);
|
||||
bin = new BinaryFileWriter(World.ItemDataPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = new AsyncWriter(World.ItemIndexPath, false);
|
||||
tdb = new AsyncWriter(World.ItemTypesPath, false);
|
||||
bin = new AsyncWriter(World.ItemDataPath, true);
|
||||
}
|
||||
|
||||
idx.Write( ( int ) items.Count );
|
||||
idx.Write(items.Count);
|
||||
|
||||
DateTime n = DateTime.UtcNow;
|
||||
DateTime n = DateTime.UtcNow;
|
||||
|
||||
foreach ( Item item in items.Values ) {
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal && (item.LastMoved + item.DecayTime) <= n)
|
||||
{
|
||||
_decayQueue.Enqueue( item );
|
||||
}
|
||||
foreach (Item item in items.Values)
|
||||
{
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal && item.LastMoved + item.DecayTime <= n)
|
||||
_decayQueue.Enqueue(item);
|
||||
|
||||
long start = bin.Position;
|
||||
long start = bin.Position;
|
||||
|
||||
idx.Write( ( int ) item.m_TypeRef );
|
||||
idx.Write( ( int ) item.Serial );
|
||||
idx.Write( ( long ) start );
|
||||
idx.Write(item.m_TypeRef);
|
||||
idx.Write(item.Serial);
|
||||
idx.Write(start);
|
||||
|
||||
item.Serialize( bin );
|
||||
item.Serialize(bin);
|
||||
|
||||
metrics?.OnItemSaved( ( int ) ( bin.Position - start ) );
|
||||
metrics?.OnItemSaved((int)(bin.Position - start));
|
||||
|
||||
idx.Write( ( int ) ( bin.Position - start ) );
|
||||
idx.Write((int)(bin.Position - start));
|
||||
|
||||
item.FreeCache();
|
||||
}
|
||||
item.FreeCache();
|
||||
}
|
||||
|
||||
tdb.Write( ( int ) World.m_ItemTypes.Count );
|
||||
for ( int i = 0; i < World.m_ItemTypes.Count; ++i )
|
||||
tdb.Write( World.m_ItemTypes[i].FullName );
|
||||
tdb.Write(World.m_ItemTypes.Count);
|
||||
for (int i = 0; i < World.m_ItemTypes.Count; ++i)
|
||||
tdb.Write(World.m_ItemTypes[i].FullName);
|
||||
|
||||
idx.Close();
|
||||
tdb.Close();
|
||||
bin.Close();
|
||||
}
|
||||
idx.Close();
|
||||
tdb.Close();
|
||||
bin.Close();
|
||||
}
|
||||
|
||||
protected void SaveGuilds(SaveMetrics metrics)
|
||||
{
|
||||
GenericWriter idx;
|
||||
GenericWriter bin;
|
||||
protected void SaveGuilds(SaveMetrics metrics)
|
||||
{
|
||||
GenericWriter idx;
|
||||
GenericWriter bin;
|
||||
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter( World.GuildIndexPath, false );
|
||||
bin = new BinaryFileWriter( World.GuildDataPath, true );
|
||||
} else {
|
||||
idx = new AsyncWriter( World.GuildIndexPath, false );
|
||||
bin = new AsyncWriter( World.GuildDataPath, true );
|
||||
}
|
||||
if (UseSequentialWriters)
|
||||
{
|
||||
idx = new BinaryFileWriter(World.GuildIndexPath, false);
|
||||
bin = new BinaryFileWriter(World.GuildDataPath, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
idx = new AsyncWriter(World.GuildIndexPath, false);
|
||||
bin = new AsyncWriter(World.GuildDataPath, true);
|
||||
}
|
||||
|
||||
idx.Write( ( int ) BaseGuild.List.Count );
|
||||
foreach ( BaseGuild guild in BaseGuild.List.Values ) {
|
||||
long start = bin.Position;
|
||||
idx.Write(BaseGuild.List.Count);
|
||||
foreach (BaseGuild guild in BaseGuild.List.Values)
|
||||
{
|
||||
long start = bin.Position;
|
||||
|
||||
idx.Write( ( int ) 0 );//guilds have no typeid
|
||||
idx.Write( ( int ) guild.Id );
|
||||
idx.Write( ( long ) start );
|
||||
idx.Write(0); //guilds have no typeid
|
||||
idx.Write(guild.Id);
|
||||
idx.Write(start);
|
||||
|
||||
guild.Serialize( bin );
|
||||
guild.Serialize(bin);
|
||||
|
||||
metrics?.OnGuildSaved( ( int ) ( bin.Position - start ) );
|
||||
metrics?.OnGuildSaved((int)(bin.Position - start));
|
||||
|
||||
idx.Write( ( int ) ( bin.Position - start ) );
|
||||
}
|
||||
idx.Write((int)(bin.Position - start));
|
||||
}
|
||||
|
||||
idx.Close();
|
||||
bin.Close();
|
||||
}
|
||||
idx.Close();
|
||||
bin.Close();
|
||||
}
|
||||
|
||||
public override void ProcessDecay() {
|
||||
while ( _decayQueue.Count > 0 ) {
|
||||
Item item = _decayQueue.Dequeue();
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
while (_decayQueue.Count > 0)
|
||||
{
|
||||
Item item = _decayQueue.Dequeue();
|
||||
|
||||
if ( item.OnDecay() ) {
|
||||
item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (item.OnDecay()) item.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,76 +20,75 @@
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public class Point3DList
|
||||
{
|
||||
private Point3D[] m_List;
|
||||
public class Point3DList
|
||||
{
|
||||
private static Point3D[] m_EmptyList = new Point3D[0];
|
||||
private Point3D[] m_List;
|
||||
|
||||
public Point3DList()
|
||||
{
|
||||
m_List = new Point3D[8];
|
||||
Count = 0;
|
||||
}
|
||||
public Point3DList()
|
||||
{
|
||||
m_List = new Point3D[8];
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public int Count { get; private set; }
|
||||
public int Count{ get; private set; }
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
Count = 0;
|
||||
}
|
||||
public Point3D Last => m_List[Count - 1];
|
||||
|
||||
public Point3D Last => m_List[Count - 1];
|
||||
public Point3D this[int index] => m_List[index];
|
||||
|
||||
public Point3D this[int index] => m_List[index];
|
||||
public void Clear()
|
||||
{
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public void Add( int x, int y, int z )
|
||||
{
|
||||
if ( (Count + 1) > m_List.Length )
|
||||
{
|
||||
Point3D[] old = m_List;
|
||||
m_List = new Point3D[old.Length * 2];
|
||||
public void Add(int x, int y, int z)
|
||||
{
|
||||
if (Count + 1 > m_List.Length)
|
||||
{
|
||||
Point3D[] old = m_List;
|
||||
m_List = new Point3D[old.Length * 2];
|
||||
|
||||
for ( int i = 0; i < old.Length; ++i )
|
||||
m_List[i] = old[i];
|
||||
}
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
m_List[i] = old[i];
|
||||
}
|
||||
|
||||
m_List[Count].m_X = x;
|
||||
m_List[Count].m_Y = y;
|
||||
m_List[Count].m_Z = z;
|
||||
++Count;
|
||||
}
|
||||
m_List[Count].m_X = x;
|
||||
m_List[Count].m_Y = y;
|
||||
m_List[Count].m_Z = z;
|
||||
++Count;
|
||||
}
|
||||
|
||||
public void Add( Point3D p )
|
||||
{
|
||||
if ( (Count + 1) > m_List.Length )
|
||||
{
|
||||
Point3D[] old = m_List;
|
||||
m_List = new Point3D[old.Length * 2];
|
||||
public void Add(Point3D p)
|
||||
{
|
||||
if (Count + 1 > m_List.Length)
|
||||
{
|
||||
Point3D[] old = m_List;
|
||||
m_List = new Point3D[old.Length * 2];
|
||||
|
||||
for ( int i = 0; i < old.Length; ++i )
|
||||
m_List[i] = old[i];
|
||||
}
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
m_List[i] = old[i];
|
||||
}
|
||||
|
||||
m_List[Count].m_X = p.m_X;
|
||||
m_List[Count].m_Y = p.m_Y;
|
||||
m_List[Count].m_Z = p.m_Z;
|
||||
++Count;
|
||||
}
|
||||
m_List[Count].m_X = p.m_X;
|
||||
m_List[Count].m_Y = p.m_Y;
|
||||
m_List[Count].m_Z = p.m_Z;
|
||||
++Count;
|
||||
}
|
||||
|
||||
private static Point3D[] m_EmptyList = new Point3D[0];
|
||||
public Point3D[] ToArray()
|
||||
{
|
||||
if (Count == 0)
|
||||
return m_EmptyList;
|
||||
|
||||
public Point3D[] ToArray()
|
||||
{
|
||||
if ( Count == 0 )
|
||||
return m_EmptyList;
|
||||
Point3D[] list = new Point3D[Count];
|
||||
|
||||
Point3D[] list = new Point3D[Count];
|
||||
for (int i = 0; i < Count; ++i)
|
||||
list[i] = m_List[i];
|
||||
|
||||
for ( int i = 0; i < Count; ++i )
|
||||
list[i] = m_List[i];
|
||||
Count = 0;
|
||||
|
||||
Count = 0;
|
||||
|
||||
return list;
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
}
|
||||
}
|
||||
218
Server/Poison.cs
218
Server/Poison.cs
|
|
@ -23,113 +23,115 @@ using System.Collections.Generic;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
[Parsable]
|
||||
public abstract class Poison
|
||||
[Parsable]
|
||||
public abstract class Poison
|
||||
{
|
||||
/*public abstract TimeSpan Interval{ get; }
|
||||
public abstract TimeSpan Duration{ get; }*/
|
||||
public abstract string Name{ get; }
|
||||
public abstract int Level{ get; }
|
||||
|
||||
public static Poison Lesser => GetPoison("Lesser");
|
||||
public static Poison Regular => GetPoison("Regular");
|
||||
public static Poison Greater => GetPoison("Greater");
|
||||
public static Poison Deadly => GetPoison("Deadly");
|
||||
public static Poison Lethal => GetPoison("Lethal");
|
||||
|
||||
public static List<Poison> Poisons{ get; } = new List<Poison>();
|
||||
|
||||
public abstract Timer ConstructTimer(Mobile m);
|
||||
/*public abstract void OnDamage( Mobile m, ref object state );*/
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
/*public abstract TimeSpan Interval{ get; }
|
||||
public abstract TimeSpan Duration{ get; }*/
|
||||
public abstract string Name { get; }
|
||||
public abstract int Level { get; }
|
||||
public abstract Timer ConstructTimer( Mobile m );
|
||||
/*public abstract void OnDamage( Mobile m, ref object state );*/
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
|
||||
|
||||
public static void Register( Poison reg )
|
||||
{
|
||||
string regName = reg.Name.ToLower();
|
||||
|
||||
for ( int i = 0; i < Poisons.Count; i++ )
|
||||
{
|
||||
if ( reg.Level == Poisons[i].Level )
|
||||
throw new Exception( "A poison with that level already exists." );
|
||||
if ( regName == Poisons[i].Name.ToLower() )
|
||||
throw new Exception( "A poison with that name already exists." );
|
||||
}
|
||||
|
||||
Poisons.Add( reg );
|
||||
}
|
||||
|
||||
public static Poison Lesser => GetPoison( "Lesser" );
|
||||
public static Poison Regular => GetPoison( "Regular" );
|
||||
public static Poison Greater => GetPoison( "Greater" );
|
||||
public static Poison Deadly => GetPoison( "Deadly" );
|
||||
public static Poison Lethal => GetPoison( "Lethal" );
|
||||
|
||||
public static List<Poison> Poisons { get; } = new List<Poison>();
|
||||
|
||||
public static Poison Parse( string value )
|
||||
{
|
||||
Poison p = null;
|
||||
|
||||
int plevel;
|
||||
|
||||
if ( int.TryParse( value, out plevel ) )
|
||||
p = GetPoison( plevel );
|
||||
|
||||
if ( p == null )
|
||||
p = GetPoison( value );
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Poison GetPoison( int level )
|
||||
{
|
||||
for ( int i = 0; i < Poisons.Count; ++i )
|
||||
{
|
||||
Poison p = Poisons[i];
|
||||
|
||||
if ( p.Level == level )
|
||||
return p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Poison GetPoison( string name )
|
||||
{
|
||||
for ( int i = 0; i < Poisons.Count; ++i )
|
||||
{
|
||||
Poison p = Poisons[i];
|
||||
|
||||
if ( Utility.InsensitiveCompare( p.Name, name ) == 0 )
|
||||
return p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Serialize( Poison p, GenericWriter writer )
|
||||
{
|
||||
if ( p == null )
|
||||
{
|
||||
writer.Write( (byte)0 );
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write( (byte)1 );
|
||||
writer.Write( (byte)p.Level );
|
||||
}
|
||||
}
|
||||
|
||||
public static Poison Deserialize( GenericReader reader )
|
||||
{
|
||||
switch ( reader.ReadByte() )
|
||||
{
|
||||
case 1: return GetPoison( reader.ReadByte() );
|
||||
case 2:
|
||||
//no longer used, safe to remove?
|
||||
reader.ReadInt();
|
||||
reader.ReadDouble();
|
||||
reader.ReadInt();
|
||||
reader.ReadTimeSpan();
|
||||
break;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static void Register(Poison reg)
|
||||
{
|
||||
string regName = reg.Name.ToLower();
|
||||
|
||||
for (int i = 0; i < Poisons.Count; i++)
|
||||
{
|
||||
if (reg.Level == Poisons[i].Level)
|
||||
throw new Exception("A poison with that level already exists.");
|
||||
if (regName == Poisons[i].Name.ToLower())
|
||||
throw new Exception("A poison with that name already exists.");
|
||||
}
|
||||
|
||||
Poisons.Add(reg);
|
||||
}
|
||||
|
||||
public static Poison Parse(string value)
|
||||
{
|
||||
Poison p = null;
|
||||
|
||||
int plevel;
|
||||
|
||||
if (int.TryParse(value, out plevel))
|
||||
p = GetPoison(plevel);
|
||||
|
||||
if (p == null)
|
||||
p = GetPoison(value);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Poison GetPoison(int level)
|
||||
{
|
||||
for (int i = 0; i < Poisons.Count; ++i)
|
||||
{
|
||||
Poison p = Poisons[i];
|
||||
|
||||
if (p.Level == level)
|
||||
return p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static Poison GetPoison(string name)
|
||||
{
|
||||
for (int i = 0; i < Poisons.Count; ++i)
|
||||
{
|
||||
Poison p = Poisons[i];
|
||||
|
||||
if (Utility.InsensitiveCompare(p.Name, name) == 0)
|
||||
return p;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static void Serialize(Poison p, GenericWriter writer)
|
||||
{
|
||||
if (p == null)
|
||||
{
|
||||
writer.Write((byte)0);
|
||||
}
|
||||
else
|
||||
{
|
||||
writer.Write((byte)1);
|
||||
writer.Write((byte)p.Level);
|
||||
}
|
||||
}
|
||||
|
||||
public static Poison Deserialize(GenericReader reader)
|
||||
{
|
||||
switch (reader.ReadByte())
|
||||
{
|
||||
case 1: return GetPoison(reader.ReadByte());
|
||||
case 2:
|
||||
//no longer used, safe to remove?
|
||||
reader.ReadInt();
|
||||
reader.ReadDouble();
|
||||
reader.ReadInt();
|
||||
reader.ReadTimeSpan();
|
||||
break;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -20,26 +20,26 @@
|
|||
|
||||
namespace Server.Prompts
|
||||
{
|
||||
public abstract class Prompt
|
||||
{
|
||||
private static int m_Serials;
|
||||
public abstract class Prompt
|
||||
{
|
||||
private static int m_Serials;
|
||||
|
||||
public int Serial { get; }
|
||||
protected Prompt()
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial = ++m_Serials;
|
||||
} while (Serial == 0);
|
||||
}
|
||||
|
||||
protected Prompt()
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial = ++m_Serials;
|
||||
} while ( Serial == 0 );
|
||||
}
|
||||
public int Serial{ get; }
|
||||
|
||||
public virtual void OnCancel( Mobile from )
|
||||
{
|
||||
}
|
||||
public virtual void OnCancel(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnResponse( Mobile from, string text )
|
||||
{
|
||||
}
|
||||
}
|
||||
public virtual void OnResponse(Mobile from, string text)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -22,78 +22,79 @@ using Server.Network;
|
|||
|
||||
namespace Server
|
||||
{
|
||||
public class QuestArrow
|
||||
{
|
||||
public Mobile Mobile { get; }
|
||||
public class QuestArrow
|
||||
{
|
||||
public QuestArrow(Mobile m, Mobile t)
|
||||
{
|
||||
Running = true;
|
||||
Mobile = m;
|
||||
Target = t;
|
||||
}
|
||||
|
||||
public Mobile Target { get; }
|
||||
public QuestArrow(Mobile m, Mobile t, int x, int y) : this(m, t)
|
||||
{
|
||||
Update(x, y);
|
||||
}
|
||||
|
||||
public bool Running { get; private set; }
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Update( Target.X, Target.Y );
|
||||
}
|
||||
public Mobile Target{ get; }
|
||||
|
||||
public void Update( int x, int y )
|
||||
{
|
||||
if ( !Running )
|
||||
return;
|
||||
public bool Running{ get; private set; }
|
||||
|
||||
NetState ns = Mobile.NetState;
|
||||
public void Update()
|
||||
{
|
||||
Update(Target.X, Target.Y);
|
||||
}
|
||||
|
||||
if ( ns == null )
|
||||
return;
|
||||
public void Update(int x, int y)
|
||||
{
|
||||
if (!Running)
|
||||
return;
|
||||
|
||||
if ( ns.HighSeas )
|
||||
ns.Send( new SetArrowHS( x, y, Target.Serial ) );
|
||||
else
|
||||
ns.Send( new SetArrow( x, y ) );
|
||||
}
|
||||
NetState ns = Mobile.NetState;
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
Stop( Target.X, Target.Y );
|
||||
}
|
||||
if (ns == null)
|
||||
return;
|
||||
|
||||
public void Stop( int x, int y )
|
||||
{
|
||||
if ( !Running )
|
||||
return;
|
||||
if (ns.HighSeas)
|
||||
ns.Send(new SetArrowHS(x, y, Target.Serial));
|
||||
else
|
||||
ns.Send(new SetArrow(x, y));
|
||||
}
|
||||
|
||||
Mobile.ClearQuestArrow();
|
||||
public void Stop()
|
||||
{
|
||||
Stop(Target.X, Target.Y);
|
||||
}
|
||||
|
||||
NetState ns = Mobile.NetState;
|
||||
public void Stop(int x, int y)
|
||||
{
|
||||
if (!Running)
|
||||
return;
|
||||
|
||||
if ( ns != null ) {
|
||||
if ( ns.HighSeas )
|
||||
ns.Send( new CancelArrowHS( x, y, Target.Serial ) );
|
||||
else
|
||||
ns.Send( new CancelArrow() );
|
||||
}
|
||||
Mobile.ClearQuestArrow();
|
||||
|
||||
Running = false;
|
||||
OnStop();
|
||||
}
|
||||
NetState ns = Mobile.NetState;
|
||||
|
||||
public virtual void OnStop()
|
||||
{
|
||||
}
|
||||
if (ns != null)
|
||||
{
|
||||
if (ns.HighSeas)
|
||||
ns.Send(new CancelArrowHS(x, y, Target.Serial));
|
||||
else
|
||||
ns.Send(new CancelArrow());
|
||||
}
|
||||
|
||||
public virtual void OnClick( bool rightClick )
|
||||
{
|
||||
}
|
||||
Running = false;
|
||||
OnStop();
|
||||
}
|
||||
|
||||
public QuestArrow( Mobile m, Mobile t )
|
||||
{
|
||||
Running = true;
|
||||
Mobile = m;
|
||||
Target = t;
|
||||
}
|
||||
public virtual void OnStop()
|
||||
{
|
||||
}
|
||||
|
||||
public QuestArrow( Mobile m, Mobile t, int x, int y ) : this( m, t )
|
||||
{
|
||||
Update( x, y );
|
||||
}
|
||||
}
|
||||
public virtual void OnClick(bool rightClick)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue