Overwrite

Complete Overwrite of the Folder with the free shard. ServUO 57.3 has been added.
This commit is contained in:
Unstable Kitsune
2023-11-28 23:20:26 -05:00
parent 3cd54811de
commit b918192e4e
11608 changed files with 2644205 additions and 47 deletions

214
Server/AggressorInfo.cs Normal file
View File

@@ -0,0 +1,214 @@
#region References
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
#endregion
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;
private bool m_Queued;
private static readonly Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>();
public static AggressorInfo Create(Mobile attacker, Mobile defender, bool criminal)
{
AggressorInfo info;
if (m_Pool.Count > 0)
{
info = m_Pool.Dequeue();
info.m_Attacker = attacker;
info.m_Defender = defender;
info.m_CanReportMurder = criminal;
info.m_CriminalAggression = criminal;
info.m_Queued = false;
info.Refresh();
}
else
{
info = new AggressorInfo(attacker, defender, criminal);
}
return info;
}
public void Free()
{
if (m_Queued)
{
return;
}
m_Queued = true;
m_Pool.Enqueue(this);
}
private AggressorInfo(Mobile attacker, Mobile defender, bool criminal)
{
m_Attacker = attacker;
m_Defender = defender;
m_CanReportMurder = criminal;
m_CriminalAggression = criminal;
Refresh();
}
private static TimeSpan m_ExpireDelay = TimeSpan.FromMinutes(2.0);
public static TimeSpan ExpireDelay { get { return m_ExpireDelay; } set { m_ExpireDelay = value; } }
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();
}
}
public bool Expired
{
get
{
if (m_Queued)
{
DumpAccess();
}
return (m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= (m_LastCombatTime + m_ExpireDelay));
}
}
public bool CriminalAggression
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_CriminalAggression;
}
set
{
if (m_Queued)
{
DumpAccess();
}
m_CriminalAggression = value;
}
}
public Mobile Attacker
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_Attacker;
}
}
public Mobile Defender
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_Defender;
}
}
public DateTime LastCombatTime
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_LastCombatTime;
}
}
public bool Reported
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_Reported;
}
set
{
if (m_Queued)
{
DumpAccess();
}
m_Reported = value;
}
}
public bool CanReportMurder
{
get
{
if (m_Queued)
{
DumpAccess();
}
return m_CanReportMurder;
}
set
{
if (m_Queued)
{
DumpAccess();
}
m_CanReportMurder = value;
}
}
public void Refresh()
{
if (m_Queued)
{
DumpAccess();
}
m_LastCombatTime = DateTime.UtcNow;
m_Reported = false;
}
}
}

63
Server/AssemblyInfo.cs Normal file
View File

@@ -0,0 +1,63 @@
#region References
using System.Reflection;
using System.Resources;
using System.Runtime.InteropServices;
#endregion
//
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
//
[assembly: AssemblyTitle("ServUO Server")]
[assembly: AssemblyDescription("Ultima Online Server Emulator")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("The ServUO Team")]
[assembly: AssemblyProduct("")]
[assembly: AssemblyCopyright("")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
//
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Revision and Build Numbers
// by using the '*' as shown below:
[assembly: AssemblyVersion("0.5.*")]
//
// In order to sign your assembly you must specify a key to use. Refer to the
// Microsoft .NET Framework documentation for more information on assembly signing.
//
// Use the attributes below to control which key is used for signing.
//
// Notes:
// (*) If no key is specified, the assembly is not signed.
// (*) KeyName refers to a key that has been installed in the Crypto Service
// Provider (CSP) on your machine. KeyFile refers to a file which contains
// a key.
// (*) If the KeyFile and the KeyName values are both specified, the
// following processing occurs:
// (1) If the KeyName can be found in the CSP, that key is used.
// (2) If the KeyName does not exist and the KeyFile does exist, the key
// in the KeyFile is installed into the CSP and used.
// (*) In order to create a KeyFile, you can use the sn.exe (Strong Name) utility.
// When specifying the KeyFile, the location of the KeyFile should be
// relative to the project output directory which is
// %Project Directory%\obj\<configuration>. For example, if your KeyFile is
// located in the project directory, you would specify the AssemblyKeyFile
// attribute as [assembly: AssemblyKeyFile("..\\..\\mykey.snk")]
// (*) Delay Signing is an advanced option - see the Microsoft .NET Framework
// documentation for more information on this.
//
[assembly: AssemblyDelaySign(false)]
[assembly: AssemblyKeyFile("")]
[assembly: AssemblyKeyName("")]
[assembly: ComVisible(false)]
[assembly: NeutralResourcesLanguage("en")]

206
Server/Attributes.cs Normal file
View File

@@ -0,0 +1,206 @@
#region References
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
#endregion
namespace Server
{
[AttributeUsage(AttributeTargets.Property)]
public class HueAttribute : Attribute
{ }
[AttributeUsage(AttributeTargets.Property)]
public class BodyAttribute : Attribute
{ }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Interface)]
public class PropertyObjectAttribute : Attribute
{ }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class NoSortAttribute : Attribute
{ }
[AttributeUsage(AttributeTargets.Method)]
public class CallPriorityAttribute : Attribute
{
public int Priority { get; set; }
public CallPriorityAttribute(int priority)
{
Priority = priority;
}
}
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 (y == null)
{
return -1;
}
var xPriority = GetPriority(x);
var yPriority = GetPriority(y);
if (xPriority > yPriority)
return 1;
if (xPriority < yPriority)
return -1;
return 0;
}
private int GetPriority(MethodInfo mi)
{
var objs = mi.GetCustomAttributes(typeof(CallPriorityAttribute), true);
if (objs == null)
{
return 0;
}
if (objs.Length == 0)
{
return 0;
}
CallPriorityAttribute attr = objs[0] as CallPriorityAttribute;
if (attr == null)
{
return 0;
}
return attr.Priority;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class TypeAliasAttribute : Attribute
{
private readonly string[] m_Aliases;
public string[] Aliases { get { return m_Aliases; } }
public TypeAliasAttribute(params string[] aliases)
{
m_Aliases = aliases;
}
}
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
public class ParsableAttribute : Attribute
{ }
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
public class CustomEnumAttribute : Attribute
{
private readonly string[] m_Names;
public string[] Names { get { return m_Names; } }
public CustomEnumAttribute(string[] names)
{
m_Names = names;
}
}
[AttributeUsage(AttributeTargets.Class)]
public class DeleteConfirmAttribute : Attribute
{
public string Message { get; set; }
public DeleteConfirmAttribute()
: this("Are you sure you wish to delete this item?")
{ }
public DeleteConfirmAttribute(string message)
{
Message = message;
}
public static bool Find<T>(out string message) where T : class
{
return Find(typeof(T), out message);
}
public static bool Find(object o, out string message)
{
return Find(o.GetType(), out message);
}
public static bool Find(Type t, out string message)
{
var attrs = t.GetCustomAttributes(typeof(DeleteConfirmAttribute), true);
if (attrs.Length > 0)
{
message = String.Join("\n", attrs.OfType<DeleteConfirmAttribute>().Select(a => a.Message));
return true;
}
message = String.Empty;
return false;
}
}
[AttributeUsage(AttributeTargets.Constructor)]
public class ConstructableAttribute : Attribute
{
public AccessLevel AccessLevel { get; set; }
public ConstructableAttribute()
: this(AccessLevel.Player) //Lowest accesslevel for current functionality (Level determined by access to [add)
{ }
public ConstructableAttribute(AccessLevel accessLevel)
{
AccessLevel = accessLevel;
}
}
[AttributeUsage(AttributeTargets.Property)]
public class CommandPropertyAttribute : Attribute
{
private readonly AccessLevel m_ReadLevel;
private readonly AccessLevel m_WriteLevel;
private readonly bool m_ReadOnly;
public AccessLevel ReadLevel { get { return m_ReadLevel; } }
public AccessLevel WriteLevel { get { return m_WriteLevel; } }
public bool ReadOnly { get { return m_ReadOnly; } }
public CommandPropertyAttribute(AccessLevel level, bool readOnly)
{
m_ReadLevel = level;
m_ReadOnly = readOnly;
}
public CommandPropertyAttribute(AccessLevel level)
: this(level, level)
{ }
public CommandPropertyAttribute(AccessLevel readLevel, AccessLevel writeLevel)
{
m_ReadLevel = readLevel;
m_WriteLevel = writeLevel;
}
}
}

115
Server/BaseVendor.cs Normal file
View File

@@ -0,0 +1,115 @@
#region References
using System.Collections.Generic;
#endregion
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;
}
return l.MySerial.CompareTo(r.MySerial);
}
}
public class BuyItemResponse
{
private readonly Serial m_Serial;
private readonly int m_Amount;
public BuyItemResponse(Serial serial, int amount)
{
m_Serial = serial;
m_Amount = amount;
}
public Serial Serial { get { return m_Serial; } }
public int Amount { get { return m_Amount; } }
}
public class SellItemResponse
{
private readonly Item m_Item;
private readonly int m_Amount;
public SellItemResponse(Item i, int amount)
{
m_Item = i;
m_Amount = amount;
}
public Item Item { get { return m_Item; } }
public int Amount { get { return m_Amount; } }
}
public class SellItemState
{
private readonly Item m_Item;
private readonly int m_Price;
private readonly string m_Name;
public SellItemState(Item item, int price, string name)
{
m_Item = item;
m_Price = price;
m_Name = name;
}
public Item Item { get { return m_Item; } }
public int Price { get { return m_Price; } }
public string Name { get { return m_Name; } }
}
public class BuyItemState
{
private readonly Serial m_ContSer;
private readonly Serial m_MySer;
private readonly int m_ItemID;
private readonly int m_Amount;
private readonly int m_Hue;
private readonly int m_Price;
private readonly string m_Desc;
public BuyItemState(string name, Serial cont, Serial serial, int price, int amount, int itemID, int hue)
{
m_Desc = name;
m_ContSer = cont;
m_MySer = serial;
m_Price = price;
m_Amount = amount;
m_ItemID = itemID;
m_Hue = hue;
}
public int Price { get { return m_Price; } }
public Serial MySerial { get { return m_MySer; } }
public Serial ContainerSerial { get { return m_ContSer; } }
public int ItemID { get { return m_ItemID; } }
public int Amount { get { return m_Amount; } }
public int Hue { get { return m_Hue; } }
public string Description { get { return m_Desc; } }
}
}

226
Server/Body.cs Normal file
View File

@@ -0,0 +1,226 @@
#region References
using System;
using System.IO;
#endregion
namespace Server
{
public enum BodyType : byte
{
Empty,
Monster,
Sea,
Animal,
Human,
Equipment
}
public struct Body
{
private readonly int m_BodyID;
private static readonly BodyType[] m_Types;
static Body()
{
if (File.Exists("Data/bodyTable.cfg"))
{
using (StreamReader ip = new StreamReader("Data/bodyTable.cfg"))
{
m_Types = new BodyType[0x1000];
string line;
while ((line = ip.ReadLine()) != null)
{
if (line.Length == 0 || line.StartsWith("#"))
{
continue;
}
var split = line.Split('\t');
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");
m_Types = new BodyType[0];
}
}
public Body(int bodyID)
{
m_BodyID = bodyID;
}
public BodyType Type
{
get
{
if (m_BodyID >= 0 && m_BodyID < m_Types.Length)
{
return m_Types[m_BodyID];
}
else
{
return BodyType.Empty;
}
}
}
public bool IsHuman
{
get
{
return (m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Human && m_BodyID != 402 &&
m_BodyID != 403 && m_BodyID != 607 && m_BodyID != 608 && m_BodyID != 970)
#region Stygian Abyss
|| m_BodyID == 694 || m_BodyID == 695
#endregion
;
}
}
public bool IsMale
{
get
{
return m_BodyID == 183 || m_BodyID == 185 || m_BodyID == 400 || m_BodyID == 402 || m_BodyID == 605 ||
m_BodyID == 607 || m_BodyID == 750
#region Stygian Abyss
|| m_BodyID == 666 || m_BodyID == 694
#endregion
;
}
}
public bool IsFemale
{
get
{
return m_BodyID == 184 || m_BodyID == 186 || m_BodyID == 401 || m_BodyID == 403 || m_BodyID == 606 ||
m_BodyID == 608 || m_BodyID == 751
#region Stygian Abyss
|| m_BodyID == 667 || m_BodyID == 695
#endregion
#region High Seas
|| m_BodyID == 1253
#endregion
;
}
}
public bool IsGhost
{
get
{
return m_BodyID == 402 || m_BodyID == 403 || m_BodyID == 607 || m_BodyID == 608 || m_BodyID == 970
#region Stygian Abyss
|| m_BodyID == 694 || m_BodyID == 695
#endregion
;
}
}
public bool IsMonster { get { return m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Monster; } }
public bool IsAnimal { get { return m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Animal; } }
public bool IsEmpty { get { return m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Empty; } }
public bool IsSea { get { return m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Sea; } }
public bool IsEquipment { get { return m_BodyID >= 0 && m_BodyID < m_Types.Length && m_Types[m_BodyID] == BodyType.Equipment; } }
#region Stygian Abyss
public bool IsGargoyle { get { return m_BodyID == 666 || m_BodyID == 667 || m_BodyID == 694 || m_BodyID == 695; } }
#endregion
public int BodyID { get { return m_BodyID; } }
public static implicit operator int(Body a)
{
return a.m_BodyID;
}
public static implicit operator Body(int a)
{
return new Body(a);
}
public override string ToString()
{
return string.Format("0x{0:X}", m_BodyID);
}
public override int GetHashCode()
{
return m_BodyID;
}
public override bool Equals(object o)
{
if (o == null || !(o is Body))
{
return false;
}
return ((Body)o).m_BodyID == m_BodyID;
}
public static bool operator ==(Body l, Body r)
{
return l.m_BodyID == r.m_BodyID;
}
public static bool operator !=(Body l, Body r)
{
return l.m_BodyID != r.m_BodyID;
}
public static bool operator >(Body l, Body r)
{
return l.m_BodyID > r.m_BodyID;
}
public static bool operator >=(Body l, Body r)
{
return l.m_BodyID >= r.m_BodyID;
}
public static bool operator <(Body l, Body r)
{
return l.m_BodyID < r.m_BodyID;
}
public static bool operator <=(Body l, Body r)
{
return l.m_BodyID <= r.m_BodyID;
}
}
}

313
Server/ClientVersion.cs Normal file
View File

@@ -0,0 +1,313 @@
#region References
using System;
using System.Collections;
using System.Text;
#endregion
namespace Server
{
public enum ClientType
{
Regular,
UOTD,
God,
SA
}
public class ClientVersion : IComparable, IComparer
{
private readonly int m_Major;
private readonly int m_Minor;
private readonly int m_Revision;
private readonly int m_Patch;
private readonly ClientType m_Type;
private readonly string m_SourceString;
public int Major { get { return m_Major; } }
public int Minor { get { return m_Minor; } }
public int Revision { get { return m_Revision; } }
public int Patch { get { return m_Patch; } }
public ClientType Type { get { return m_Type; } }
public string SourceString { get { return m_SourceString; } }
public ClientVersion(int maj, int min, int rev, int pat)
: this(maj, min, rev, pat, ClientType.Regular)
{ }
public ClientVersion(int maj, int min, int rev, int pat, ClientType type)
{
m_Major = maj;
m_Minor = min;
m_Revision = rev;
m_Patch = pat;
m_Type = type;
if (m_Type != ClientType.SA && m_Major >= 67)
{
m_Type = ClientType.SA;
}
m_SourceString = _ToStringImpl();
}
public static bool operator ==(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) == 0);
}
public static bool operator !=(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) != 0);
}
public static bool operator >=(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) >= 0);
}
public static bool operator >(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) > 0);
}
public static bool operator <=(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) <= 0);
}
public static bool operator <(ClientVersion l, ClientVersion r)
{
return (Compare(l, r) < 0);
}
public override int GetHashCode()
{
return m_Major ^ m_Minor ^ m_Revision ^ m_Patch ^ (int)m_Type;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
ClientVersion v = obj as ClientVersion;
if (v == null)
{
return false;
}
return m_Major == v.m_Major && m_Minor == v.m_Minor && m_Revision == v.m_Revision && m_Patch == v.m_Patch &&
m_Type == v.m_Type;
}
private string _ToStringImpl()
{
StringBuilder builder = new StringBuilder(16);
builder.Append(m_Major);
builder.Append('.');
builder.Append(m_Minor);
builder.Append('.');
builder.Append(m_Revision);
if (m_Major <= 5 && m_Minor <= 0 && m_Revision <= 6) //Anything before 5.0.7
{
if (m_Patch > 0)
{
builder.Append((char)('a' + (m_Patch - 1)));
}
}
else
{
builder.Append('.');
builder.Append(m_Patch);
}
if (m_Type != ClientType.Regular)
{
builder.Append(' ');
builder.Append(m_Type.ToString());
}
return builder.ToString();
}
public override string ToString()
{
return _ToStringImpl();
}
public ClientVersion(string fmt)
{
m_SourceString = fmt;
try
{
fmt = fmt.ToLower();
int br1 = fmt.IndexOf('.');
int br2 = fmt.IndexOf('.', br1 + 1);
int br3 = br2 + 1;
while (br3 < fmt.Length && Char.IsDigit(fmt, br3))
{
br3++;
}
m_Major = Utility.ToInt32(fmt.Substring(0, br1));
m_Minor = Utility.ToInt32(fmt.Substring(br1 + 1, br2 - br1 - 1));
m_Revision = Utility.ToInt32(fmt.Substring(br2 + 1, br3 - br2 - 1));
if (br3 < fmt.Length)
{
if (m_Major <= 5 && m_Minor <= 0 && m_Revision <= 6) //Anything before 5.0.7
{
if (!Char.IsWhiteSpace(fmt, br3))
{
m_Patch = (fmt[br3] - 'a') + 1;
}
}
else
{
m_Patch = Utility.ToInt32(fmt.Substring(br3 + 1, fmt.Length - br3 - 1));
}
}
if (m_Major >= 67)
{
m_Type = ClientType.SA;
}
else if(fmt.IndexOf("god") >= 0 || fmt.IndexOf("gq") >= 0)
{
m_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)
{
m_Type = ClientType.UOTD;
}
else
{
m_Type = ClientType.Regular;
}
}
catch
{
m_Major = 0;
m_Minor = 0;
m_Revision = 0;
m_Patch = 0;
m_Type = ClientType.Regular;
}
}
public int CompareTo(object obj)
{
if (obj == null)
{
return 1;
}
ClientVersion o = obj as ClientVersion;
if (o == null)
{
throw new ArgumentException();
}
if (m_Major > o.m_Major)
{
return 1;
}
else if (m_Major < o.m_Major)
{
return -1;
}
else if (m_Minor > o.m_Minor)
{
return 1;
}
else if (m_Minor < o.m_Minor)
{
return -1;
}
else if (m_Revision > o.m_Revision)
{
return 1;
}
else if (m_Revision < o.m_Revision)
{
return -1;
}
else if (m_Patch > o.m_Patch)
{
return 1;
}
else if (m_Patch < o.m_Patch)
{
return -1;
}
else
{
return 0;
}
}
public static bool IsNull(object x)
{
return ReferenceEquals(x, null);
}
public int Compare(object x, object y)
{
if (IsNull(x) && IsNull(y))
{
return 0;
}
else if (IsNull(x))
{
return -1;
}
else if (IsNull(y))
{
return 1;
}
ClientVersion a = x as ClientVersion;
ClientVersion b = y as ClientVersion;
if (IsNull(a) || IsNull(b))
{
throw new ArgumentException();
}
return a.CompareTo(b);
}
public static int Compare(ClientVersion a, ClientVersion b)
{
if (IsNull(a) && IsNull(b))
{
return 0;
}
else if (IsNull(a))
{
return -1;
}
else if (IsNull(b))
{
return 1;
}
return a.CompareTo(b);
}
}
}

288
Server/Commands.cs Normal file
View File

@@ -0,0 +1,288 @@
#region References
using System;
using System.Collections.Generic;
using Server.Network;
#endregion
namespace Server.Commands
{
public delegate void CommandEventHandler(CommandEventArgs e);
public class CommandEventArgs : EventArgs
{
private readonly Mobile m_Mobile;
private readonly string m_Command;
private readonly string m_ArgString;
private readonly string[] m_Arguments;
public Mobile Mobile { get { return m_Mobile; } }
public string Command { get { return m_Command; } }
public string ArgString { get { return m_ArgString; } }
public string[] Arguments { get { return m_Arguments; } }
public int Length { get { return m_Arguments.Length; } }
public string GetString(int index)
{
if (index < 0 || index >= m_Arguments.Length)
{
return "";
}
return m_Arguments[index];
}
public int GetInt32(int index)
{
if (index < 0 || index >= m_Arguments.Length)
{
return 0;
}
return Utility.ToInt32(m_Arguments[index]);
}
public bool GetBoolean(int index)
{
if (index < 0 || index >= m_Arguments.Length)
{
return false;
}
return Utility.ToBoolean(m_Arguments[index]);
}
public double GetDouble(int index)
{
if (index < 0 || index >= m_Arguments.Length)
{
return 0.0;
}
return Utility.ToDouble(m_Arguments[index]);
}
public TimeSpan GetTimeSpan(int index)
{
if (index < 0 || index >= m_Arguments.Length)
{
return TimeSpan.Zero;
}
return Utility.ToTimeSpan(m_Arguments[index]);
}
public CommandEventArgs(Mobile mobile, string command, string argString, string[] arguments)
{
m_Mobile = mobile;
m_Command = command;
m_ArgString = argString;
m_Arguments = arguments;
}
}
public class CommandEntry : IComparable
{
private readonly string m_Command;
private readonly CommandEventHandler m_Handler;
private readonly AccessLevel m_AccessLevel;
public string Command { get { return m_Command; } }
public CommandEventHandler Handler { get { return m_Handler; } }
public AccessLevel AccessLevel { get { return m_AccessLevel; } }
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)
{
m_Command = command;
m_Handler = handler;
m_AccessLevel = accessLevel;
}
public int CompareTo(object obj)
{
if (obj == this)
{
return 0;
}
else if (obj == null)
{
return 1;
}
CommandEntry e = obj as CommandEntry;
if (e == null)
{
throw new ArgumentException();
}
return m_Command.CompareTo(e.m_Command);
}
}
public static class CommandSystem
{
private static string m_Prefix = "[";
public static string Prefix { get { return m_Prefix; } set { m_Prefix = value; } }
public static string[] Split(string value)
{
var array = value.ToCharArray();
var list = new List<string>();
int start = 0, end = 0;
while (start < array.Length)
{
char c = array[start];
if (c == '"')
{
++start;
end = start;
while (end < array.Length)
{
if (array[end] != '"' || array[end - 1] == '\\')
{
++end;
}
else
{
break;
}
}
list.Add(value.Substring(start, end - start));
start = end + 2;
}
else if (c != ' ')
{
end = start;
while (end < array.Length)
{
if (array[end] != ' ')
{
++end;
}
else
{
break;
}
}
list.Add(value.Substring(start, end - start));
start = end + 1;
}
else
{
++start;
}
}
return list.ToArray();
}
private static readonly Dictionary<string, CommandEntry> m_Entries;
public static Dictionary<string, CommandEntry> Entries { get { return m_Entries; } }
static CommandSystem()
{
m_Entries = new Dictionary<string, CommandEntry>(StringComparer.OrdinalIgnoreCase);
}
public static void Register(string command, AccessLevel access, CommandEventHandler handler)
{
m_Entries[command] = new CommandEntry(command, handler, access);
}
private static AccessLevel m_BadCommandIngoreLevel = AccessLevel.Player;
public static AccessLevel BadCommandIgnoreLevel { get { return m_BadCommandIngoreLevel; } set { m_BadCommandIngoreLevel = value; } }
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(m_Prefix) || type == MessageType.Command)
{
if (type != MessageType.Command)
{
text = text.Substring(m_Prefix.Length);
}
int indexOf = text.IndexOf(' ');
string command;
string[] args;
string argString;
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];
}
CommandEntry entry = null;
m_Entries.TryGetValue(command, out 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 <= m_BadCommandIngoreLevel)
{
return false;
}
from.SendMessage("You do not have access to that command.");
}
}
else
{
if (from.AccessLevel <= m_BadCommandIngoreLevel)
{
return false;
}
from.SendMessage("That is not a valid command.");
}
return true;
}
return false;
}
}
}

832
Server/Config.cs Normal file
View File

@@ -0,0 +1,832 @@
#region References
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
#endregion
namespace Server
{
public static class Config
{
public sealed class Entry : IEquatable<Entry>, IComparable<Entry>
{
public int FileIndex { get; private set; }
public string File { get; private set; }
public string Scope { get; private set; }
public string Desc { get; set; }
public string Key { get; set; }
public string Value { get; set; }
public bool UseDefault { get; set; }
public Entry(string file, int fileIndex, string scope, string desc, string key, string value, bool useDefault)
{
File = file;
FileIndex = fileIndex;
Scope = scope;
Desc = desc;
Key = key;
Value = value;
UseDefault = useDefault;
}
public override string ToString()
{
return String.Format("{0}.{1}{2}={3}", Scope, UseDefault ? "@" : "", Key, Value);
}
public override int GetHashCode()
{
unchecked
{
var hash = -1;
hash = (hash * 397) ^ File.GetHashCode();
hash = (hash * 397) ^ Scope.GetHashCode();
hash = (hash * 397) ^ Key.GetHashCode();
return hash;
}
}
public override bool Equals(object obj)
{
return obj is Entry && Equals((Entry)obj);
}
public bool Equals(Entry other)
{
if (ReferenceEquals(other, null))
{
return false;
}
if (ReferenceEquals(other, this))
{
return true;
}
return Insensitive.Equals(File, other.File) && //
Insensitive.Equals(Scope, other.Scope) && //
Insensitive.Equals(Key, other.Key);
}
public int CompareTo(Entry other)
{
if (other == null)
{
return -1;
}
if (!Insensitive.Equals(File, other.File))
{
return Insensitive.Compare(File, other.File);
}
return FileIndex.CompareTo(other.FileIndex);
}
}
private static bool _Initialized;
private static readonly string _Path = Path.Combine(Core.BaseDirectory, "Config");
private static readonly IFormatProvider _NumFormatter = CultureInfo.InvariantCulture.NumberFormat;
private static readonly Dictionary<string, Entry> _Entries =
new Dictionary<string, Entry>(StringComparer.OrdinalIgnoreCase);
public static IEnumerable<Entry> Entries { get { return _Entries.Values; } }
public static void Load()
{
if (_Initialized)
{
return;
}
_Initialized = true;
if (!Directory.Exists(_Path))
{
Directory.CreateDirectory(_Path);
}
IEnumerable<string> files;
try
{
files = Directory.EnumerateFiles(_Path, "*.cfg", SearchOption.AllDirectories);
}
catch (DirectoryNotFoundException)
{
Console.WriteLine("Warning: No configuration files found!");
return;
}
foreach (var path in files)
{
try
{
LoadFile(path);
}
catch (Exception e)
{
Console.WriteLine("Warning: Failed to load configuration file:");
Console.WriteLine(path);
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine(e.Message);
Utility.PopColor();
ConsoleKey key;
do
{
Console.WriteLine("Ignore this warning? (y/n)");
key = Console.ReadKey(true).Key;
}
while (key != ConsoleKey.Y && key != ConsoleKey.N);
if (key != ConsoleKey.Y)
{
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
Core.Kill(false);
return;
}
}
}
if (Core.Debug)
{
Console.WriteLine();
foreach (var e in _Entries.Values)
{
Console.WriteLine(e);
}
Console.WriteLine();
}
}
private static void LoadFile(string path)
{
var info = new FileInfo(path);
if (!info.Exists)
{
throw new FileNotFoundException();
}
path = info.Directory != null ? info.Directory.FullName : String.Empty;
var io = path.IndexOf(_Path, StringComparison.OrdinalIgnoreCase);
if (io > -1)
{
path = path.Substring(io + _Path.Length);
}
var parts = path.Split(Path.DirectorySeparatorChar);
var scope = String.Join(".", parts.Where(p => !String.IsNullOrWhiteSpace(p)));
if (scope.Length > 0)
{
scope += ".";
}
scope += Path.GetFileNameWithoutExtension(info.Name);
var lines = File.ReadAllLines(info.FullName);
var desc = new List<string>(0x10);
for (int i = 0, idx = 0; i < lines.Length; i++)
{
var line = lines[i].Trim();
if (String.IsNullOrWhiteSpace(line))
{
desc.Clear();
continue;
}
if (line.StartsWith("#"))
{
desc.Add(line.TrimStart('#').Trim());
continue;
}
var useDef = false;
if (line.StartsWith("@"))
{
useDef = true;
line = line.TrimStart('@').Trim();
}
io = line.IndexOf('=');
if (io < 0)
{
throw new FormatException(String.Format("Bad format at line {0}", i + 1));
}
var key = line.Substring(0, io);
var val = line.Substring(io + 1);
if (String.IsNullOrWhiteSpace(key))
{
throw new NullReferenceException(String.Format("Key can not be null at line {0}", i + 1));
}
key = key.Trim();
if (String.IsNullOrEmpty(val))
{
val = null;
}
var e = new Entry(info.FullName, idx++, scope, String.Join(String.Empty, desc), key, val, useDef);
_Entries[String.Format("{0}.{1}", e.Scope, e.Key)] = e;
desc.Clear();
}
}
public static void Save()
{
if (!_Initialized)
{
Load();
}
if (!Directory.Exists(_Path))
{
Directory.CreateDirectory(_Path);
}
foreach (var g in _Entries.Values.ToLookup(e => e.File))
{
try
{
SaveFile(g.Key, g.OrderBy(e => e.FileIndex));
}
catch (Exception e)
{
Console.WriteLine("Warning: Failed to save configuration file:");
Console.WriteLine(g.Key);
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine(e.Message);
Utility.PopColor();
}
}
}
private static void SaveFile(string path, IEnumerable<Entry> entries)
{
var content = new StringBuilder(0x1000);
var line = new StringBuilder(0x80);
foreach (var e in entries)
{
content.AppendLine();
if (!String.IsNullOrWhiteSpace(e.Desc))
{
line.Clear();
foreach (var word in e.Desc.Split(' '))
{
if ((line + word).Length > 100)
{
content.AppendLine(String.Format("# {0}", line));
line.Clear();
}
line.AppendFormat("{0} ", word);
}
if (line.Length > 0)
{
content.AppendLine(String.Format("# {0}", line));
line.Clear();
}
}
content.AppendLine(String.Format("{0}{1}={2}", e.UseDefault ? "@" : String.Empty, e.Key, e.Value));
}
File.WriteAllText(path, content.ToString());
}
public static Entry Find(string key)
{
Entry e;
_Entries.TryGetValue(key, out e);
return e;
}
private static void InternalSet(string key, string value)
{
var e = Find(key);
if (e != null)
{
e.Value = value;
e.UseDefault = false;
return;
}
var parts = key.Split('.');
var realKey = parts.Last();
parts = parts.Take(parts.Length - 1).ToArray();
var file = new FileInfo(Path.Combine(_Path, Path.Combine(parts) + ".cfg"));
var idx = _Entries.Values.Where(o => Insensitive.Equals(o.File, file.FullName)).Select(o => o.FileIndex).DefaultIfEmpty().Max();
_Entries[key] = new Entry(file.FullName, idx, String.Join(".", parts), String.Empty, realKey, value, false);
}
public static void Set(string key, string value)
{
InternalSet(key, value);
}
public static void Set(string key, char value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, sbyte value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, byte value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, short value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, ushort value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, int value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, uint value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, long value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, ulong value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, float value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, double value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, decimal value)
{
InternalSet(key, value.ToString(_NumFormatter));
}
public static void Set(string key, bool value)
{
InternalSet(key, value ? "true" : "false");
}
public static void Set(string key, TimeSpan value)
{
InternalSet(key, value.ToString());
}
public static void Set(string key, DateTime value)
{
InternalSet(key, value.ToString(CultureInfo.InvariantCulture));
}
public static void SetEnum<T>(string key, T value) where T : struct, IConvertible
{
var t = typeof(T);
if (!t.IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
var vals = Enum.GetValues(t).Cast<T>();
foreach (T o in vals.Where(o => o.Equals(value)))
{
InternalSet(key, o.ToString(CultureInfo.InvariantCulture));
return;
}
throw new ArgumentException("Enumerated value not found");
}
private static void Warn<T>(string key)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("Config: Warning, '{0}' invalid value for '{1}'", typeof(T), key);
Utility.PopColor();
}
private static string InternalGet(string key)
{
if (!_Initialized)
{
Load();
}
Entry e;
if (_Entries.TryGetValue(key, out e) && e != null)
{
return e.UseDefault ? null : e.Value;
}
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("Config: Warning, using default value for {0}", key);
Utility.PopColor();
return null;
}
public static string Get(string key, string defaultValue)
{
return InternalGet(key) ?? defaultValue;
}
public static sbyte Get(string key, sbyte defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || sbyte.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<sbyte>(key);
return defaultValue;
}
public static byte Get(string key, byte defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || byte.TryParse(value, NumberStyles.Any & ~NumberStyles.AllowLeadingSign, _NumFormatter, out ret))
{
return ret;
}
Warn<byte>(key);
return defaultValue;
}
public static short Get(string key, short defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || short.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<short>(key);
return defaultValue;
}
public static ushort Get(string key, ushort defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || ushort.TryParse(value, NumberStyles.Any & ~NumberStyles.AllowLeadingSign, _NumFormatter, out ret))
{
return ret;
}
Warn<ushort>(key);
return defaultValue;
}
public static int Get(string key, int defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || int.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<int>(key);
return defaultValue;
}
public static uint Get(string key, uint defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || uint.TryParse(value, NumberStyles.Any & ~NumberStyles.AllowLeadingSign, _NumFormatter, out ret))
{
return ret;
}
Warn<uint>(key);
return defaultValue;
}
public static long Get(string key, long defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || long.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<long>(key);
return defaultValue;
}
public static ulong Get(string key, ulong defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || ulong.TryParse(value, NumberStyles.Any & ~NumberStyles.AllowLeadingSign, _NumFormatter, out ret))
{
return ret;
}
Warn<ulong>(key);
return defaultValue;
}
public static float Get(string key, float defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || float.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<float>(key);
return defaultValue;
}
public static double Get(string key, double defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || double.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<double>(key);
return defaultValue;
}
public static decimal Get(string key, decimal defaultValue)
{
var ret = defaultValue;
var value = InternalGet(key);
if (value == null || decimal.TryParse(value, NumberStyles.Any, _NumFormatter, out ret))
{
return ret;
}
Warn<decimal>(key);
return defaultValue;
}
public static bool Get(string key, bool defaultValue)
{
var value = InternalGet(key);
if (value == null)
{
return defaultValue;
}
if (Regex.IsMatch(value, @"(true|yes|on|1|enabled)", RegexOptions.IgnoreCase))
{
return true;
}
if (Regex.IsMatch(value, @"(false|no|off|0|disabled)", RegexOptions.IgnoreCase))
{
return false;
}
Warn<bool>(key);
return defaultValue;
}
public static TimeSpan Get(string key, TimeSpan defaultValue)
{
var value = InternalGet(key);
TimeSpan ts;
if (TimeSpan.TryParse(value, out ts))
{
return ts;
}
Warn<TimeSpan>(key);
return defaultValue;
}
public static DateTime Get(string key, DateTime defaultValue)
{
var value = InternalGet(key);
DateTime dt;
if (DateTime.TryParse(value, out dt))
{
return dt;
}
Warn<DateTime>(key);
return defaultValue;
}
public static Type Get(string key, Type defaultValue)
{
var value = InternalGet(key);
var t = FindType(value);
if (t != null)
{
return t;
}
Warn<Type>(key);
return defaultValue;
}
public static T GetEnum<T>(string key, T defaultValue) where T : struct, IConvertible
{
if (!typeof(T).IsEnum)
{
throw new ArgumentException("T must be an enumerated type");
}
var value = InternalGet(key);
if (value == null)
{
return defaultValue;
}
value = value.Trim();
var vals = Enum.GetValues(typeof(T)).Cast<T>();
foreach (var o in vals.Where(o => Insensitive.Equals(value, o.ToString(CultureInfo.InvariantCulture))))
{
return o;
}
Warn<T>(key);
return defaultValue;
}
public static T GetDelegate<T>(string key, T defaultValue)
{
if (!typeof(MulticastDelegate).IsAssignableFrom(typeof(T).BaseType))
{
throw new ArgumentException("T must be a delegate type");
}
var value = InternalGet(key);
if (value == null)
{
return defaultValue;
}
value = value.Trim();
var i = value.LastIndexOf('.');
if (i <= 0)
{
Warn<T>(key);
return defaultValue;
}
try
{
var method = value.Substring(i + 1);
var target = FindType(value.Remove(i));
if (target != null)
{
var info = target.GetMethod(method, (BindingFlags)0x38);
if (info != null)
{
return (T)(object)Delegate.CreateDelegate(typeof(T), info);
}
}
}
catch
{ }
Warn<T>(key);
return defaultValue;
}
private static Type FindType(string value)
{
var type = Type.GetType(value, false);
if (type != null)
{
return type;
}
if (value.IndexOf('.') < 0)
{
return ScriptCompiler.FindTypeByName(value);
}
return ScriptCompiler.FindTypeByFullName(value);
}
}
}

View File

@@ -0,0 +1,275 @@
#region References
using System;
using System.Collections.Generic;
using System.Linq;
#endregion
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" />
/// </summary>
public class ContextMenu : IDisposable
{
public bool IsDisposed { get; private set; }
/// <summary>
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
/// </summary>
public Mobile From { get; private set; }
/// <summary>
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
/// </summary>
public IEntity Target { get; private set; }
/// <summary>
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
/// </summary>
public ContextMenuEntry[] Entries { get; private set; }
/// <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, IEntity target)
{
From = from;
Target = target;
var list = new List<ContextMenuEntry>();
if (target is Mobile)
{
((Mobile)target).GetContextMenuEntries(from, list);
}
else if (target is Item)
{
((Item)target).GetContextMenuEntries(from, list);
}
EventSink.InvokeContextMenu(new ContextMenuEventArgs(From, Target, list));
foreach (var e in list)
{
e.Owner = this;
}
Entries = list.ToArray();
list.Clear();
list.TrimExcess();
}
~ContextMenu()
{
Dispose();
}
/// <summary>
/// Returns true if this ContextMenu requires packet version 2.
/// </summary>
public bool RequiresNewPacket { get { return Entries.Any(t => t.Number < 3000000 || t.Number > 3032767); } }
public void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
if (Entries != null)
{
foreach (var e in Entries.Where(e => e != null))
{
e.Dispose();
}
Entries = null;
}
if (From != null)
{
if (From.ContextMenu == this)
{
From.ContextMenu = null;
}
From = null;
}
Target = null;
}
public static bool Display(Mobile m, IEntity target)
{
if (m == null || target == null || m.Map != target.Map)
{
return false;
}
if (target is Mobile && !Utility.InUpdateRange(m, target.Location))
{
return false;
}
if (target is Item && !Utility.InUpdateRange(m, ((Item)target).GetWorldLocation()))
{
return false;
}
if (!m.CheckContextMenuDisplay(target))
{
return false;
}
var c = new ContextMenu(m, target);
if (c.Entries.Length <= 0)
{
return false;
}
if (target is Item)
{
var root = ((Item)target).RootParent;
if (root is Mobile && root != m && ((Mobile)root).AccessLevel >= m.AccessLevel)
{
foreach (var e in c.Entries.Where(e => !e.NonLocalUse))
{
e.Enabled = false;
}
}
}
m.ContextMenu = c;
return true;
}
/// <summary>
/// Returns the proper index of Enhanced Client Context Menu when sent from the icon on
/// the vendors status bar. Only known are Bank, Bulk Order Info and Bribe
/// </summary>
/// <param name="index">pre-described index sent by client. Must be 0x64 or higher</param>
/// <returns>actual index of pre-desribed index from client</returns>
public int GetIndexEC(int index)
{
int number = index;
switch (index)
{
case 0x0078:
number = 3006105;
break; // Bank
case 0x0193:
number = 3006152;
break; // Bulk Order Info
case 0x01A3:
number = 1152294;
break; // Bribe
case 0x032A:
number = 3000197;
break; // Add Party Member
case 0x032B:
number = 3000198;
break; // Remove Party Member
case 0x012D:
number = 3006130;
break; // Tame
case 0x082:
number = 3006107;
break; // Command: Guard
case 0x083:
number = 3006108;
break; // Command: Follow
case 0x086:
number = 3006111;
break; // Command: Kill
case 0x087:
number = 3006114;
break; // Command: Stay
case 0x089:
number = 3006112;
break; // Command: Stop
case 0x0140:
number = 1113797;
break; // Enable PVP Warning TODO: Not Enabled
case 0x025A:
number = 3006205;
break; // Release Co-Ownership TODO: Not Enabled
case 0x025C:
number = 3006207;
break; // Leave House
case 0x0196:
number = 3006156;
break; // Quest Conversation
case 0x0194:
number = 3006154;
break; // View Quest Log
case 0x0195:
number = 3006155;
break; // Cancel Quest
case 0x0321:
number = 3006169;
break; // Toggle Quest Item
case 0x01A0:
number = 1114299;
break; // Open Item Insurance Menu
case 0x01A2:
number = 3006201;
break; // Toggle Item Insurance
case 0x0396:
number = 1115022;
break; // Open Titles Menu
case 0x0393:
number = 1049594;
break; // Loyalty Rating
case 0x0134:
number = 3006157;
break; // Cancel Protection
case 0x03F2:
number = 1152531;
break; // Void Pool
case 0x03F5:
number = 1154112;
break; // Allow Trades
case 0x03F6:
number = 1154113;
break; // Refuse Trades
case 0x0334:
number = 3006168;
break; // Siege Bless Item
}
if (index >= 0x64)
{
for (int i = 0; i < Entries.Length; i++)
{
if (Entries[i].Number == number)
{
return i;
}
}
}
return index;
}
}
}

View File

@@ -0,0 +1,141 @@
#region References
using System;
using Server.Network;
#endregion
namespace Server.ContextMenus
{
/// <summary>
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
/// <seealso cref="ContextMenu" />
/// </summary>
public class ContextMenuEntry : IDisposable
{
public bool IsDisposed { get; private 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 <see cref="ContextMenu" /> that owns this entry.
/// </summary>
public ContextMenu Owner { get; set; }
/// <summary>
/// Gets or sets the localization number containing the name of this entry.
/// </summary>
public int Number { get; set; }
/// <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 the color for this entry. Format is A1-R5-G5-B5.
/// </summary>
public int Color { 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 a value indicating if non local use of this entry is permitted.
/// </summary>
public virtual bool NonLocalUse { get { return false; } }
/// <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>
/// 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;
}
Range = range;
Enabled = true;
Color = 0xFFFF;
}
~ContextMenuEntry()
{
Dispose();
}
/// <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 and the entry is disabled.
/// </summary>
public virtual void OnClickDisabled()
{ }
public void Dispose()
{
if (IsDisposed)
{
return;
}
IsDisposed = true;
OnDispose();
if (Owner != null && Owner.Entries != null)
{
for (var i = 0; i < Owner.Entries.Length; i++)
{
if (Owner.Entries[i] == this)
{
Owner.Entries[i] = null;
}
}
}
Owner = null;
}
protected virtual void OnDispose()
{ }
}
}

View File

@@ -0,0 +1,18 @@
namespace Server.ContextMenus
{
public class OpenBackpackEntry : ContextMenuEntry
{
private readonly Mobile m_Mobile;
public OpenBackpackEntry(Mobile m)
: base(6145)
{
m_Mobile = m;
}
public override void OnClick()
{
m_Mobile.Use(m_Mobile.Backpack);
}
}
}

View File

@@ -0,0 +1,21 @@
namespace Server.ContextMenus
{
public class PaperdollEntry : ContextMenuEntry
{
private readonly Mobile m_Mobile;
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);
}
}
}
}

View File

@@ -0,0 +1,80 @@
#region References
using Server;
using Server.Gumps;
#endregion
namespace CustomsFramework
{
public class BaseCore : SaveData, ICustomsEntity, ISerializable
{
public static event BaseCoreEventHandler OnEnabledChanged;
private bool _Enabled;
public BaseCore()
{ }
public BaseCore(CustomSerial serial)
: base(serial)
{ }
[CommandProperty(AccessLevel.Developer)]
public bool Enabled
{
get { return _Enabled; }
set
{
if (value != _Enabled)
{
_Enabled = value;
if (OnEnabledChanged != null)
{
OnEnabledChanged(new BaseCoreEventArgs(this));
}
}
}
}
public override string Name { get { return @"Base Core"; } }
public virtual string Description { get { return @"Base Core, inherit from this class and override the interface items."; } }
public virtual string Version { get { return "1.0"; } }
public virtual AccessLevel EditLevel { get { return AccessLevel.Developer; } }
// TODO: Implement Custom Systems Control
public virtual Gump SettingsGump { get { return null; } }
public virtual bool ShardControlEnabled { get { return false; } }
public override string ToString()
{
return Name;
}
public override void Prep()
{ }
public override void Delete()
{ }
public override void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
// Version 0
writer.Write(_Enabled);
}
public override void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
_Enabled = reader.ReadBool();
break;
}
}
}
}
}

View File

@@ -0,0 +1,188 @@
#region References
using System;
using Server;
using Server.Gumps;
#endregion
namespace CustomsFramework
{
public class BaseModule : SaveData, ICustomsEntity, ISerializable
{
private Mobile _LinkedMobile;
private Item _LinkedItem;
private DateTime _CreatedTime;
private DateTime _LastEditedTime;
public BaseModule()
{ }
public BaseModule(Mobile from)
{
LinkMobile(from);
}
public BaseModule(Item item)
{
LinkItem(item);
}
public BaseModule(CustomSerial serial)
: base(serial)
{ }
public override string Name { get { return @"Base Module"; } }
public virtual string Description { get { return "Base Module, inherit from this class and override all interface items."; } }
public virtual string Version { get { return "1.0"; } }
public virtual AccessLevel EditLevel { get { return AccessLevel.Developer; } }
public virtual Gump SettingsGump { get { return null; } }
[CommandProperty(AccessLevel.Administrator)]
public Mobile LinkedMobile { get { return _LinkedMobile; } set { LinkMobile(value); } }
[CommandProperty(AccessLevel.Administrator)]
public Item LinkedItem { get { return _LinkedItem; } set { LinkItem(value); } }
[CommandProperty(AccessLevel.Administrator)]
public DateTime CreatedTime { get { return _CreatedTime; } }
[CommandProperty(AccessLevel.Administrator)]
public DateTime LastEditedTime { get { return _LastEditedTime; } }
public override string ToString()
{
return Name;
}
public override void Prep()
{ }
public override void Delete()
{
if (_LinkedMobile != null)
{
_LinkedMobile.Modules.Remove(this);
_LinkedMobile = null;
}
if (_LinkedItem != null)
{
_LinkedItem.Modules.Remove(this);
_LinkedItem = null;
}
}
public void Update()
{
_LastEditedTime = DateTime.UtcNow;
}
public bool LinkMobile(Mobile from)
{
if (_LinkedMobile != null || _LinkedMobile == from)
{
return false;
}
else
{
if (!from.Modules.Contains(this))
{
from.Modules.Add(this);
}
_LinkedMobile = from;
Update();
return true;
}
}
public bool LinkItem(Item item)
{
if (_LinkedItem != null || _LinkedItem == item)
{
return false;
}
else
{
if (!item.Modules.Contains(this))
{
item.Modules.Add(this);
}
_LinkedItem = item;
Update();
return true;
}
}
public bool UnlinkMobile()
{
if (_LinkedMobile == null)
{
return false;
}
else
{
if (_LinkedMobile.Modules.Contains(this))
{
_LinkedMobile.Modules.Remove(this);
}
_LinkedMobile = null;
Update();
return true;
}
}
public bool UnlinkItem()
{
if (_LinkedItem == null)
{
return false;
}
else
{
if (_LinkedItem.Modules.Contains(this))
{
_LinkedItem.Modules.Remove(this);
}
_LinkedItem = null;
Update();
return true;
}
}
public override void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
// Version 0
writer.Write(_LinkedMobile);
writer.Write(_LinkedItem);
writer.Write(_CreatedTime);
writer.Write(_LastEditedTime);
}
public override void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
LinkedMobile = reader.ReadMobile();
LinkedItem = reader.ReadItem();
_CreatedTime = reader.ReadDateTime();
_LastEditedTime = reader.ReadDateTime();
break;
}
}
}
}
}

View File

@@ -0,0 +1,53 @@
#region References
using Server;
using Server.Gumps;
#endregion
namespace CustomsFramework
{
public class BaseService : SaveData, ICustomsEntity, ISerializable
{
public BaseService()
{ }
public BaseService(CustomSerial serial)
: base(serial)
{ }
public override string Name { get { return @"Base Service"; } }
public virtual string Description { get { return @"Base Service, inherit from this class and override the interface items."; } }
public virtual string Version { get { return "1.0"; } }
public virtual AccessLevel EditLevel { get { return AccessLevel.Developer; } }
public virtual Gump SettingsGump { get { return null; } }
public override string ToString()
{
return Name;
}
public override void Prep()
{ }
public override void Delete()
{ }
public override void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
//Version 0
}
public override void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
break;
}
}
}
}
}

View File

@@ -0,0 +1,34 @@
#region References
using System;
#endregion
namespace CustomsFramework
{
public delegate void BaseCoreEventHandler(BaseCoreEventArgs e);
public delegate void BaseModuleEventHandler(BaseModuleEventArgs e);
public class BaseCoreEventArgs : EventArgs
{
private readonly BaseCore m_Core;
public BaseCoreEventArgs(BaseCore core)
{
m_Core = core;
}
public BaseCore Core { get { return m_Core; } }
}
public class BaseModuleEventArgs : EventArgs
{
private readonly BaseModule m_Module;
public BaseModuleEventArgs(BaseModule module)
{
m_Module = module;
}
public BaseModule Module { get { return m_Module; } }
}
}

View File

@@ -0,0 +1,113 @@
#region References
using System;
using Server;
#endregion
namespace CustomsFramework
{
public class SaveData : ICustomsEntity, IComparable<SaveData>, ISerializable
{
#region CompareTo
public int CompareTo(ICustomsEntity other)
{
if (other == null)
{
return -1;
}
return _Serial.CompareTo(other.Serial);
}
public int CompareTo(SaveData other)
{
return CompareTo((ICustomsEntity)other);
}
public int CompareTo(object other)
{
if (other == null || other is ICustomsEntity)
{
return CompareTo((ICustomsEntity)other);
}
throw new ArgumentException();
}
#endregion
internal int _TypeID;
int ISerializable.TypeReference { get { return _TypeID; } }
int ISerializable.SerialIdentity { get { return _Serial; } }
private bool _Deleted;
private CustomSerial _Serial;
[CommandProperty(AccessLevel.Developer)]
public bool Deleted { get { return _Deleted; } set { _Deleted = value; } }
[CommandProperty(AccessLevel.Developer)]
public CustomSerial Serial { get { return _Serial; } set { _Serial = value; } }
public virtual string Name { get { return @"Save Data"; } }
public SaveData(CustomSerial serial)
{
_Serial = serial;
Type dataType = GetType();
_TypeID = World._DataTypes.IndexOf(dataType);
if (_TypeID == -1)
{
World._DataTypes.Add(dataType);
_TypeID = World._DataTypes.Count - 1;
}
}
public SaveData()
{
_Serial = CustomSerial.NewCustom;
World.AddData(this);
Type dataType = GetType();
_TypeID = World._DataTypes.IndexOf(dataType);
if (_TypeID == -1)
{
World._DataTypes.Add(dataType);
_TypeID = World._DataTypes.Count - 1;
}
}
public virtual void Prep()
{ }
public virtual void Delete()
{ }
public virtual void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
// Version 0
writer.Write(_Deleted);
}
public virtual void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
_Deleted = reader.ReadBool();
break;
}
}
}
}
}

View File

@@ -0,0 +1,116 @@
#region References
using System;
using Server;
#endregion
namespace CustomsFramework
{
public struct CustomSerial : IComparable, IComparable<CustomSerial>
{
public static readonly CustomSerial MinusOne = new CustomSerial(-1);
public static readonly CustomSerial Zero = new CustomSerial(0);
private static CustomSerial _LastCustom = Zero;
private readonly int _Serial;
private CustomSerial(int serial)
{
_Serial = serial;
}
public static CustomSerial LastCore { get { return _LastCustom; } }
public static CustomSerial NewCustom
{
get
{
while (World.GetData(_LastCustom = (_LastCustom + 1)) != null)
{ }
return _LastCustom;
}
}
public int Value { get { return _Serial; } }
public bool IsValid { get { return (_Serial > 0); } }
public override int GetHashCode()
{
return _Serial;
}
public int CompareTo(CustomSerial other)
{
return _Serial.CompareTo(other._Serial);
}
public int CompareTo(object other)
{
if (other is CustomSerial)
{
return CompareTo((CustomSerial)other);
}
else if (other == null)
{
return -1;
}
throw new ArgumentException();
}
public override bool Equals(object obj)
{
if (obj == null || !(obj is CustomSerial))
{
return false;
}
return ((CustomSerial)obj)._Serial == _Serial;
}
public override string ToString()
{
return String.Format("0x{0:X8}", _Serial);
}
public static bool operator ==(CustomSerial first, CustomSerial second)
{
return first._Serial == second._Serial;
}
public static bool operator !=(CustomSerial first, CustomSerial second)
{
return first._Serial != second._Serial;
}
public static bool operator >(CustomSerial first, CustomSerial second)
{
return first._Serial > second._Serial;
}
public static bool operator <(CustomSerial first, CustomSerial second)
{
return first._Serial < second._Serial;
}
public static bool operator >=(CustomSerial first, CustomSerial second)
{
return first._Serial >= second._Serial;
}
public static bool operator <=(CustomSerial first, CustomSerial second)
{
return first._Serial <= second._Serial;
}
public static implicit operator int(CustomSerial serial)
{
return serial._Serial;
}
public static implicit operator CustomSerial(int serial)
{
return new CustomSerial(serial);
}
}
}

View File

@@ -0,0 +1,23 @@
#region References
using System;
#endregion
namespace CustomsFramework
{
public interface ICustomsEntry
{
CustomSerial Serial { get; }
int TypeID { get; }
long Position { get; }
int Length { get; }
}
public interface ICustomsEntity : IComparable, IComparable<ICustomsEntity>
{
CustomSerial Serial { get; }
string Name { get; }
void Delete();
void Prep();
}
}

View File

@@ -0,0 +1,55 @@
#region References
using System;
using CustomsFramework;
#endregion
namespace Server
{
public class LastEditedBy
{
private Mobile _Mobile;
private DateTime _Time;
public LastEditedBy(Mobile mobile)
{
_Mobile = mobile;
_Time = DateTime.UtcNow;
}
public LastEditedBy(GenericReader reader)
{
Deserialize(reader);
}
[CommandProperty(AccessLevel.Decorator)]
public Mobile Mobile { get { return _Mobile; } set { _Mobile = value; } }
[CommandProperty(AccessLevel.Decorator)]
public DateTime Time { get { return _Time; } set { _Time = value; } }
public void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
// Version 0
writer.Write(_Mobile);
writer.Write(_Time);
}
private void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
_Mobile = reader.ReadMobile();
_Time = reader.ReadDateTime();
break;
}
}
}
}
}

View File

@@ -0,0 +1,59 @@
#region References
using CustomsFramework;
#endregion
namespace Server
{
public class Place
{
private Map _Map;
private Point3D _Location;
public Place()
{
_Map = Map.Internal;
_Location = new Point3D(0, 0, 0);
}
public Place(Map map, Point3D location)
{
_Map = map;
_Location = location;
}
public Place(GenericReader reader)
{
Deserialize(reader);
}
[CommandProperty(AccessLevel.Decorator)]
public Map Map { get { return _Map; } set { _Map = value; } }
[CommandProperty(AccessLevel.Decorator)]
public Point3D Location { get { return _Location; } set { _Location = value; } }
public void Serialize(GenericWriter writer)
{
writer.WriteVersion(0);
// Version 0
writer.Write(_Map);
writer.Write(_Location);
}
private void Deserialize(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
_Map = reader.ReadMap();
_Location = reader.ReadPoint3D();
break;
}
}
}
}
}

View File

@@ -0,0 +1,209 @@
#region References
using System;
#endregion
namespace CustomsFramework
{
internal class Decompressor
{
#region Decompression Tree
private static readonly int[,] _huffmanTree = new int[256,2]
{
/*node*/ /*leaf0 leaf1*/
/* 0*/ {2, 1}, /* 1*/ {4, 3}, /* 2*/ {0, 5}, /* 3*/ {7, 6}, /* 4*/ {9, 8}, /* 5*/ {11, 10}, /* 6*/ {13, 12}, /* 7*/
{14, -256}, /* 8*/ {16, 15}, /* 9*/ {18, 17}, /* 10*/ {20, 19}, /* 11*/ {22, 21}, /* 12*/ {23, -1}, /* 13*/ {25, 24},
/* 14*/ {27, 26}, /* 15*/ {29, 28}, /* 16*/ {31, 30}, /* 17*/ {33, 32}, /* 18*/ {35, 34}, /* 19*/ {37, 36}, /* 20*/
{39, 38}, /* 21*/ {-64, 40}, /* 22*/ {42, 41}, /* 23*/ {44, 43}, /* 24*/ {45, -6}, /* 25*/ {47, 46}, /* 26*/ {49, 48}
, /* 27*/ {51, 50}, /* 28*/ {52, -119}, /* 29*/ {53, -32}, /* 30*/ {-14, 54}, /* 31*/ {-5, 55}, /* 32*/ {57, 56},
/* 33*/ {59, 58}, /* 34*/ {-2, 60}, /* 35*/ {62, 61}, /* 36*/ {64, 63}, /* 37*/ {66, 65}, /* 38*/ {68, 67}, /* 39*/
{70, 69}, /* 40*/ {72, 71}, /* 41*/ {73, -51}, /* 42*/ {75, 74}, /* 43*/ {77, 76}, /* 44*/ {-111, -101}, /* 45*/
{-97, -4}, /* 46*/ {79, 78}, /* 47*/ {80, -110}, /* 48*/ {-116, 81}, /* 49*/ {83, 82}, /* 50*/ {-255, 84}, /* 51*/
{86, 85}, /* 52*/ {88, 87}, /* 53*/ {90, 89}, /* 54*/ {-10, -15}, /* 55*/ {92, 91}, /* 56*/ {93, -21}, /* 57*/
{94, -117}, /* 58*/ {96, 95}, /* 59*/ {98, 97}, /* 60*/ {100, 99}, /* 61*/ {101, -114}, /* 62*/ {102, -105}, /* 63*/
{103, -26}, /* 64*/ {105, 104}, /* 65*/ {107, 106}, /* 66*/ {109, 108}, /* 67*/ {111, 110}, /* 68*/ {-3, 112},
/* 69*/ {-7, 113}, /* 70*/ {-131, 114}, /* 71*/ {-144, 115}, /* 72*/ {117, 116}, /* 73*/ {118, -20}, /* 74*/
{120, 119}, /* 75*/ {122, 121}, /* 76*/ {124, 123}, /* 77*/ {126, 125}, /* 78*/ {128, 127}, /* 79*/ {-100, 129},
/* 80*/ {-8, 130}, /* 81*/ {132, 131}, /* 82*/ {134, 133}, /* 83*/ {135, -120}, /* 84*/ {-31, 136}, /* 85*/
{138, 137}, /* 86*/ {-234, -109}, /* 87*/ {140, 139}, /* 88*/ {142, 141}, /* 89*/ {144, 143}, /* 90*/ {145, -112},
/* 91*/ {146, -19}, /* 92*/ {148, 147}, /* 93*/ {-66, 149}, /* 94*/ {-145, 150}, /* 95*/ {-65, -13}, /* 96*/
{152, 151}, /* 97*/ {154, 153}, /* 98*/ {155, -30}, /* 99*/ {157, 156}, /* 100*/ {158, -99}, /* 101*/ {160, 159},
/* 102*/ {162, 161}, /* 103*/ {163, -23}, /* 104*/ {164, -29}, /* 105*/ {165, -11}, /* 106*/ {-115, 166}, /* 107*/
{168, 167}, /* 108*/ {170, 169}, /* 109*/ {171, -16}, /* 110*/ {172, -34}, /* 111*/ {-132, 173}, /* 112*/ {-108, 174}
, /* 113*/ {-22, 175}, /* 114*/ {-9, 176}, /* 115*/ {-84, 177}, /* 116*/ {-37, -17}, /* 117*/ {178, -28}, /* 118*/
{180, 179}, /* 119*/ {182, 181}, /* 120*/ {184, 183}, /* 121*/ {186, 185}, /* 122*/ {-104, 187}, /* 123*/ {-78, 188},
/* 124*/ {-61, 189}, /* 125*/ {-178, -79}, /* 126*/ {-134, -59}, /* 127*/ {-25, 190}, /* 128*/ {-18, -83}, /* 129*/
{-57, 191}, /* 130*/ {192, -67}, /* 131*/ {193, -98}, /* 132*/ {-68, -12}, /* 133*/ {195, 194}, /* 134*/ {-128, -55},
/* 135*/ {-50, -24}, /* 136*/ {196, -70}, /* 137*/ {-33, -94}, /* 138*/ {-129, 197}, /* 139*/ {198, -74}, /* 140*/
{199, -82}, /* 141*/ {-87, -56}, /* 142*/ {200, -44}, /* 143*/ {201, -248}, /* 144*/ {-81, -163}, /* 145*/
{-123, -52}, /* 146*/ {-113, 202}, /* 147*/ {-41, -48}, /* 148*/ {-40, -122}, /* 149*/ {-90, 203}, /* 150*/
{204, -54}, /* 151*/ {-192, -86}, /* 152*/ {206, 205}, /* 153*/ {-130, 207}, /* 154*/ {208, -53}, /* 155*/
{-45, -133}, /* 156*/ {210, 209}, /* 157*/ {-91, 211}, /* 158*/ {213, 212}, /* 159*/ {-88, -106}, /* 160*/ {215, 214}
, /* 161*/ {217, 216}, /* 162*/ {-49, 218}, /* 163*/ {220, 219}, /* 164*/ {222, 221}, /* 165*/ {224, 223}, /* 166*/
{226, 225}, /* 167*/ {-102, 227}, /* 168*/ {228, -160}, /* 169*/ {229, -46}, /* 170*/ {230, -127}, /* 171*/
{231, -103}, /* 172*/ {233, 232}, /* 173*/ {234, -60}, /* 174*/ {-76, 235}, /* 175*/ {-121, 236}, /* 176*/ {-73, 237}
, /* 177*/ {238, -149}, /* 178*/ {-107, 239}, /* 179*/ {240, -35}, /* 180*/ {-27, -71}, /* 181*/ {241, -69}, /* 182*/
{-77, -89}, /* 183*/ {-118, -62}, /* 184*/ {-85, -75}, /* 185*/ {-58, -72}, /* 186*/ {-80, -63}, /* 187*/ {-42, 242},
/* 188*/ {-157, -150}, /* 189*/ {-236, -139}, /* 190*/ {-243, -126}, /* 191*/ {-214, -142}, /* 192*/ {-206, -138},
/* 193*/ {-146, -240}, /* 194*/ {-147, -204}, /* 195*/ {-201, -152}, /* 196*/ {-207, -227}, /* 197*/ {-209, -154},
/* 198*/ {-254, -153}, /* 199*/ {-156, -176}, /* 200*/ {-210, -165}, /* 201*/ {-185, -172}, /* 202*/ {-170, -195},
/* 203*/ {-211, -232}, /* 204*/ {-239, -219}, /* 205*/ {-177, -200}, /* 206*/ {-212, -175}, /* 207*/ {-143, -244},
/* 208*/ {-171, -246}, /* 209*/ {-221, -203}, /* 210*/ {-181, -202}, /* 211*/ {-250, -173}, /* 212*/ {-164, -184},
/* 213*/ {-218, -193}, /* 214*/ {-220, -199}, /* 215*/ {-249, -190}, /* 216*/ {-217, -230}, /* 217*/ {-216, -169},
/* 218*/ {-197, -191}, /* 219*/ {243, -47}, /* 220*/ {245, 244}, /* 221*/ {247, 246}, /* 222*/ {-159, -148}, /* 223*/
{249, 248}, /* 224*/ {-93, -92}, /* 225*/ {-225, -96}, /* 226*/ {-95, -151}, /* 227*/ {251, 250}, /* 228*/
{252, -241}, /* 229*/ {-36, -161}, /* 230*/ {254, 253}, /* 231*/ {-39, -135}, /* 232*/ {-124, -187}, /* 233*/
{-251, 255}, /* 234*/ {-238, -162}, /* 235*/ {-38, -242}, /* 236*/ {-125, -43}, /* 237*/ {-253, -215}, /* 238*/
{-208, -140}, /* 239*/ {-235, -137}, /* 240*/ {-237, -158}, /* 241*/ {-205, -136}, /* 242*/ {-141, -155}, /* 243*/
{-229, -228}, /* 244*/ {-168, -213}, /* 245*/ {-194, -224}, /* 246*/ {-226, -196}, /* 247*/ {-233, -183}, /* 248*/
{-167, -231}, /* 249*/ {-189, -174}, /* 250*/ {-166, -252}, /* 251*/ {-222, -198}, /* 252*/ {-179, -188}, /* 253*/
{-182, -223}, /* 254*/ {-186, -180}, /* 255*/ {-247, -245}
};
#endregion
private static int GetBit(int buf, int bit)
{
return (buf >> (bit - 1)) & 1;
}
public static bool Decompress(byte[] source, int sourceLength, byte[] destination, ref int destinationLength)
{
Array.Clear(destination, 0, destination.Length);
destinationLength = 0;
int node = 0, leaf = 0, leaf_value = 0, dest_pos = 0, bit_num = 8, src_pos = 0;
while (src_pos < sourceLength)
{
leaf = GetBit(source[src_pos], bit_num);
leaf_value = _huffmanTree[node, leaf];
// all numbers below 1 (0..-256) are codewords
// if the halt codeword has been found, skip this byte
if (leaf_value == -256)
{
bit_num = 8;
node = 0;
src_pos++;
var newsource = new byte[sourceLength - src_pos];
Array.Copy(source, src_pos, newsource, 0, sourceLength - src_pos);
source = newsource;
destinationLength = dest_pos;
return true;
}
else if (leaf_value < 1)
{
destination[dest_pos] = (byte)-leaf_value;
leaf_value = 0;
dest_pos++;
}
bit_num--;
node = leaf_value;
/* if its the end of the byte, go to the next byte */
if (bit_num < 1)
{
bit_num = 8;
src_pos++;
}
// check to see if the current codeword has no end
// if not, make it an incomplete byte
if (src_pos == sourceLength)
{
if (node != 0)
{
return false;
}
}
/*if(obj != NULL && src_pos == *src_size && node)
{
obj->incomplete_byte = src[src_pos-1];
obj->has_incomplete = 1;
}*/
}
destinationLength = dest_pos;
return false;
}
public static byte? DecompressFirstByte(byte[] source, int sourceLength)
{
int node = 0, leaf = 0, value = 0, bit = 8, index = 0;
while (index < sourceLength)
{
leaf = GetBit(source[index], bit);
value = _huffmanTree[node, leaf];
if (value == -256)
{
bit = 8;
node = 0;
index++;
continue;
}
else if (value < 1)
{
return (byte)-value;
}
bit--;
node = value;
if (bit < 1)
{
bit = 8;
index++;
}
}
return null;
}
public static void DecompressAll(byte[] src, int src_size, byte[] dest, ref int dest_size)
{
int node = 0, leaf = 0, leaf_value = 0, dest_pos = 0, bit_num = 8, src_pos = 0;
while (src_pos < src_size)
{
leaf = GetBit(src[src_pos], bit_num);
leaf_value = _huffmanTree[node, leaf];
// all numbers below 1 (0..-256) are codewords
// if the halt codeword has been found, skip this byte
if (leaf_value == -256)
{
bit_num = 8;
node = 0;
src_pos++;
continue;
}
else if (leaf_value < 1)
{
dest[dest_pos] = (byte)-leaf_value;
leaf_value = 0;
dest_pos++;
}
bit_num--;
node = leaf_value;
/* if its the end of the byte, go to the next byte */
if (bit_num < 1)
{
bit_num = 8;
src_pos++;
}
// check to see if the current codeword has no end
// if not, make it an incomplete byte
/*if(obj != NULL && src_pos == *src_size && node)
{
obj->incomplete_byte = src[src_pos-1];
obj->has_incomplete = 1;
}*/
}
dest_size = dest_pos;
return;
}
}
}

View File

@@ -0,0 +1,180 @@
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Reflection;
using System.Text;
#endregion
namespace CustomsFramework
{
public class ObjectDumper
{
private int _level;
private readonly int _indentSize;
private readonly StringBuilder _stringBuilder;
private readonly List<int> _hashListOfFoundElements;
private ObjectDumper(int indentSize)
{
_indentSize = indentSize;
_stringBuilder = new StringBuilder();
_hashListOfFoundElements = new List<int>();
}
public static string Dump(object element)
{
return Dump(element, 2);
}
public static string Dump(object element, int indentSize)
{
var instance = new ObjectDumper(indentSize);
return instance.DumpElement(element);
}
private string DumpElement(object element)
{
if (element == null || element is ValueType || element is string)
{
Write(FormatValue(element));
}
else
{
var objectType = element.GetType();
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
Write("{{{0}}}", objectType.FullName);
_hashListOfFoundElements.Add(element.GetHashCode());
_level++;
}
var enumerableElement = element as IEnumerable;
if (enumerableElement != null)
{
foreach (object item in enumerableElement)
{
if (item is IEnumerable && !(item is string))
{
_level++;
DumpElement(item);
_level--;
}
else
{
if (!AlreadyTouched(item))
{
DumpElement(item);
}
else
{
Write("{{{0}}} <-- bidirectional reference found", item.GetType().FullName);
}
}
}
}
else
{
var members = element.GetType().GetMembers(BindingFlags.Public | BindingFlags.Instance);
foreach (var memberInfo in members)
{
var fieldInfo = memberInfo as FieldInfo;
var propertyInfo = memberInfo as PropertyInfo;
if (fieldInfo == null && propertyInfo == null)
{
continue;
}
var type = fieldInfo != null ? fieldInfo.FieldType : propertyInfo.PropertyType;
object value = fieldInfo != null ? fieldInfo.GetValue(element) : propertyInfo.GetValue(element, null);
if (type.IsValueType || type == typeof(string))
{
Write("{0}: {1}", memberInfo.Name, FormatValue(value));
}
else
{
var isEnumerable = typeof(IEnumerable).IsAssignableFrom(type);
Write("{0}: {1}", memberInfo.Name, isEnumerable ? "..." : "{ }");
var alreadyTouched = !isEnumerable && AlreadyTouched(value);
_level++;
if (!alreadyTouched)
{
DumpElement(value);
}
else
{
Write("{{{0}}} <-- bidirectional reference found", value.GetType().FullName);
}
_level--;
}
}
}
if (!typeof(IEnumerable).IsAssignableFrom(objectType))
{
_level--;
}
}
return _stringBuilder.ToString();
}
private bool AlreadyTouched(object value)
{
var hash = value.GetHashCode();
for (var i = 0; i < _hashListOfFoundElements.Count; i++)
{
if (_hashListOfFoundElements[i] == hash)
{
return true;
}
}
return false;
}
private void Write(string value, params object[] args)
{
var space = new string(' ', _level * _indentSize);
if (args != null)
{
value = string.Format(value, args);
}
_stringBuilder.AppendLine(space + value);
}
private string FormatValue(object o)
{
if (o == null)
{
return ("null");
}
if (o is DateTime)
{
return (((DateTime)o).ToShortDateString());
}
if (o is string)
{
return string.Format("\"{0}\"", o);
}
if (o is ValueType)
{
return (o.ToString());
}
if (o is IEnumerable)
{
return ("...");
}
return ("{ }");
}
}
}

View File

@@ -0,0 +1,148 @@
#region References
using System;
using System.Collections.Generic;
using Server;
using Server.Network;
#endregion
namespace CustomsFramework
{
public delegate void OutgoingPacketOverrideHandler(
NetState to, PacketReader reader, ref byte[] packetBuffer, ref int packetLength);
public static class OutgoingPacketOverrides
{
public const int CallPriority = ((byte)'r') << 16 + ((byte)'a') << 8 + ((byte)'d');
private static readonly OutgoingPacketOverrideHandler[] _Handlers;
private static readonly OutgoingPacketOverrideHandler[] _ExtendedHandlersLow;
private static readonly Dictionary<int, OutgoingPacketOverrideHandler> _ExtendedHandlersHigh;
static OutgoingPacketOverrides()
{
_Handlers = new OutgoingPacketOverrideHandler[0x100];
_ExtendedHandlersLow = new OutgoingPacketOverrideHandler[0x100];
_ExtendedHandlersHigh = new Dictionary<int, OutgoingPacketOverrideHandler>();
}
[CallPriority(CallPriority)]
public static void Configure()
{
NetState.CreatedCallback += OnNetStateCreated;
}
public static void Register(int packetID, bool compressed, OutgoingPacketOverrideHandler handler)
{
_Handlers[packetID] = handler;
}
public static OutgoingPacketOverrideHandler GetHandler(int packetID)
{
return _Handlers[packetID];
}
public static void RegisterExtended(int packetID, OutgoingPacketOverrideHandler handler)
{
if (packetID >= 0 && packetID < 0x100)
{
_ExtendedHandlersLow[packetID] = handler;
}
else
{
_ExtendedHandlersHigh[packetID] = handler;
}
}
public static OutgoingPacketOverrideHandler GetExtendedHandler(int packetID)
{
if (packetID >= 0 && packetID < 0x100)
{
return _ExtendedHandlersLow[packetID];
}
else
{
OutgoingPacketOverrideHandler handler;
_ExtendedHandlersHigh.TryGetValue(packetID, out handler);
return handler;
}
}
private static void OnNetStateCreated(NetState n)
{
n.PacketEncoder = new PacketOverrideRegistryEncoder(n.PacketEncoder);
}
private class PacketOverrideRegistryEncoder : IPacketEncoder
{
private static readonly byte[] _UnpackBuffer = new byte[65535];
private readonly IPacketEncoder _Successor;
public PacketOverrideRegistryEncoder(IPacketEncoder successor)
{
_Successor = successor;
}
public void EncodeOutgoingPacket(NetState to, ref byte[] packetBuffer, ref int packetLength)
{
byte[] buffer;
int bufferLength = 0;
byte packetID;
if (to.CompressionEnabled)
{
var firstByte = Decompressor.DecompressFirstByte(packetBuffer, packetLength);
if (!firstByte.HasValue)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("Outgoing Packet Override: Unable to decompress packet!");
Utility.PopColor();
return;
}
packetID = firstByte.Value;
}
else
{
packetID = packetBuffer[0];
}
OutgoingPacketOverrideHandler handler = GetHandler(packetID) ?? GetExtendedHandler(packetID);
if (handler != null)
{
if (to.CompressionEnabled)
{
Decompressor.DecompressAll(packetBuffer, packetLength, _UnpackBuffer, ref bufferLength);
buffer = new byte[bufferLength];
Buffer.BlockCopy(_UnpackBuffer, 0, buffer, 0, bufferLength);
}
else
{
buffer = packetBuffer;
bufferLength = packetLength;
}
handler(to, new PacketReader(buffer, packetLength, true), ref packetBuffer, ref packetLength);
}
if (_Successor != null)
{
_Successor.EncodeOutgoingPacket(to, ref packetBuffer, ref packetLength);
}
}
public void DecodeIncomingPacket(NetState from, ref byte[] buffer, ref int length)
{
if (_Successor != null)
{
_Successor.DecodeIncomingPacket(from, ref buffer, ref length);
}
}
}
}
}

View File

@@ -0,0 +1,160 @@
#region References
using System;
using System.IO;
using Server;
using Server.Items;
#endregion
namespace CustomsFramework
{
public enum SaveStrategyTypes
{
StandardSaveStrategy,
DualSaveStrategy,
DynamicSaveStrategy,
ParallelSaveStrategy
}
public enum OldClientResponse
{
Ignore,
Warn,
Annoy,
LenientKick,
Kick
}
public static class Utilities
{
public static int WriteVersion(this GenericWriter writer, int version)
{
writer.Write(version);
return version;
}
public static int ReaderVersion(this GenericReader reader, int version)
{
return reader.ReadInt();
}
public static void CheckFileStructure(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
// TODO: Make this factor-in GeneralSettings AccessLevel options?
public static bool IsPlayer(this Mobile from)
{
return from.AccessLevel <= AccessLevel.VIP;
}
// TODO: Make this factor-in GeneralSettings AccessLevel options?
public static bool IsStaff(this Mobile from)
{
return from.AccessLevel >= AccessLevel.Counselor;
}
// TODO: Make this factor-in GeneralSettings AccessLevel options?
public static bool IsOwner(this Mobile from)
{
return from.AccessLevel >= AccessLevel.CoOwner;
}
public static bool IsDigit(this string text)
{
int value;
return IsDigit(text, out value);
}
public static bool IsDigit(this string text, out int value)
{
return Int32.TryParse(text, out value);
}
public static SaveStrategy GetSaveStrategy(this SaveStrategyTypes saveStrategyTypes)
{
switch (saveStrategyTypes)
{
case SaveStrategyTypes.StandardSaveStrategy:
return new StandardSaveStrategy();
case SaveStrategyTypes.DualSaveStrategy:
return new DualSaveStrategy();
case SaveStrategyTypes.DynamicSaveStrategy:
return new DynamicSaveStrategy();
case SaveStrategyTypes.ParallelSaveStrategy:
return new ParallelSaveStrategy(Core.ProcessorCount);
default:
return new StandardSaveStrategy();
}
}
public static SaveStrategyTypes GetSaveType(this SaveStrategy saveStrategy)
{
if (saveStrategy is DualSaveStrategy)
{
return SaveStrategyTypes.StandardSaveStrategy;
}
if (saveStrategy is StandardSaveStrategy)
{
return SaveStrategyTypes.StandardSaveStrategy;
}
if (saveStrategy is DynamicSaveStrategy)
{
return SaveStrategyTypes.DynamicSaveStrategy;
}
if (saveStrategy is ParallelSaveStrategy)
{
return SaveStrategyTypes.ParallelSaveStrategy;
}
return SaveStrategyTypes.StandardSaveStrategy;
}
public static void PlaceItemIn(this Container container, Item item, Point3D location)
{
container.AddItem(item);
item.Location = location;
}
public static void PlaceItemIn(this Container container, Item item, int x = 0, int y = 0, int z = 0)
{
PlaceItemIn(container, item, new Point3D(x, y, z));
}
public static Item BlessItem(this Item item)
{
item.LootType = LootType.Blessed;
return item;
}
public static Item MakeNewbie(this Item item)
{
if (!Core.AOS)
{
item.LootType = LootType.Newbied;
}
return item;
}
public static void DumpToConsole(params object[] elements)
{
Console.WriteLine();
foreach (var element in elements)
{
Console.WriteLine(ObjectDumper.Dump(element));
Console.WriteLine();
}
}
}
}

View File

@@ -0,0 +1,88 @@
#region References
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
#endregion
namespace Server.Diagnostics
{
public abstract class BaseProfile
{
public static void WriteAll<T>(TextWriter op, IEnumerable<T> profiles) where T : BaseProfile
{
var list = new List<T>(profiles);
list.Sort(delegate(T a, T b) { return -a.TotalTime.CompareTo(b.TotalTime); });
foreach (T prof in list)
{
prof.WriteTo(op);
op.WriteLine();
}
}
private readonly string _name;
private long _count;
private TimeSpan _totalTime;
private TimeSpan _peakTime;
private readonly Stopwatch _stopwatch;
public string Name { get { return _name; } }
public long Count { get { return _count; } }
public TimeSpan AverageTime { get { return TimeSpan.FromTicks(_totalTime.Ticks / Math.Max(1, _count)); } }
public TimeSpan PeakTime { get { return _peakTime; } }
public TimeSpan TotalTime { get { return _totalTime; } }
protected BaseProfile(string name)
{
_name = name;
_stopwatch = new Stopwatch();
}
public virtual void Start()
{
if (_stopwatch.IsRunning)
{
_stopwatch.Reset();
}
_stopwatch.Start();
}
public virtual void Finish()
{
TimeSpan elapsed = _stopwatch.Elapsed;
_totalTime += elapsed;
if (elapsed > _peakTime)
{
_peakTime = elapsed;
}
_count++;
_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);
}
}
}

View File

@@ -0,0 +1,35 @@
#region References
using System;
using System.Collections.Generic;
#endregion
namespace Server.Diagnostics
{
public class GumpProfile : BaseProfile
{
private static readonly Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>();
public static IEnumerable<GumpProfile> Profiles { get { return _profiles.Values; } }
public static GumpProfile Acquire(Type type)
{
if (!Core.Profiling)
{
return null;
}
GumpProfile prof;
if (!_profiles.TryGetValue(type, out prof))
{
_profiles.Add(type, prof = new GumpProfile(type));
}
return prof;
}
public GumpProfile(Type type)
: base(type.FullName)
{ }
}
}

View File

@@ -0,0 +1,99 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Runtime.CompilerServices;
using System.Threading;
#endregion
namespace Server.Diagnostics
{
public abstract class BasePacketProfile : BaseProfile
{
private long _totalLength;
public long TotalLength { get { return _totalLength; } }
public double AverageLength { get { return (double)_totalLength / Math.Max(1, Count); } }
protected BasePacketProfile(string name)
: base(name)
{ }
public void Finish(int length)
{
Finish();
_totalLength += length;
}
public override void WriteTo(TextWriter op)
{
base.WriteTo(op);
op.Write("\t{0,12:F2} {1,-12:N0}", AverageLength, TotalLength);
}
}
public class PacketSendProfile : BasePacketProfile
{
private static readonly Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>();
public static IEnumerable<PacketSendProfile> Profiles { get { return _profiles.Values; } }
[MethodImpl(MethodImplOptions.Synchronized)]
public static PacketSendProfile Acquire(Type type)
{
PacketSendProfile prof;
if (!_profiles.TryGetValue(type, out prof))
{
_profiles.Add(type, prof = new PacketSendProfile(type));
}
return prof;
}
private long _created;
public void Increment()
{
Interlocked.Increment(ref _created);
}
public PacketSendProfile(Type type)
: base(type.FullName)
{ }
public override void WriteTo(TextWriter op)
{
base.WriteTo(op);
op.Write("\t{0,12:N0}", _created);
}
}
public class PacketReceiveProfile : BasePacketProfile
{
private static readonly Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>();
public static IEnumerable<PacketReceiveProfile> Profiles { get { return _profiles.Values; } }
[MethodImpl(MethodImplOptions.Synchronized)]
public static PacketReceiveProfile Acquire(int packetId)
{
PacketReceiveProfile prof;
if (!_profiles.TryGetValue(packetId, out prof))
{
_profiles.Add(packetId, prof = new PacketReceiveProfile(packetId));
}
return prof;
}
public PacketReceiveProfile(int packetId)
: base(String.Format("0x{0:X2}", packetId))
{ }
}
}

View File

@@ -0,0 +1,35 @@
#region References
using System;
using System.Collections.Generic;
#endregion
namespace Server.Diagnostics
{
public class TargetProfile : BaseProfile
{
private static readonly Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>();
public static IEnumerable<TargetProfile> Profiles { get { return _profiles.Values; } }
public static TargetProfile Acquire(Type type)
{
if (!Core.Profiling)
{
return null;
}
TargetProfile prof;
if (!_profiles.TryGetValue(type, out prof))
{
_profiles.Add(type, prof = new TargetProfile(type));
}
return prof;
}
public TargetProfile(Type type)
: base(type.FullName)
{ }
}
}

View File

@@ -0,0 +1,50 @@
#region References
using System.Collections.Generic;
using System.IO;
#endregion
namespace Server.Diagnostics
{
public class TimerProfile : BaseProfile
{
private static readonly Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>();
public static IEnumerable<TimerProfile> Profiles { get { return _profiles.Values; } }
public static TimerProfile Acquire(string name)
{
if (!Core.Profiling)
{
return null;
}
TimerProfile prof;
if (!_profiles.TryGetValue(name, out prof))
{
_profiles.Add(name, prof = new TimerProfile(name));
}
return prof;
}
private long _created, _started, _stopped;
public long Created { get { return _created; } set { _created = value; } }
public long Started { get { return _started; } set { _started = value; } }
public long Stopped { get { return _stopped; } set { _stopped = value; } }
public TimerProfile(string name)
: base(name)
{ }
public override void WriteTo(TextWriter op)
{
base.WriteTo(op);
op.Write("\t{0,12:N0} {1,12:N0} {2,-12:N0}", _created, _started, _stopped);
}
}
}

563
Server/Effects.cs Normal file
View File

@@ -0,0 +1,563 @@
#region References
using Server.Network;
#endregion
namespace Server
{
public enum EffectLayer
{
Head = 0,
RightHand = 1,
LeftHand = 2,
Waist = 3,
LeftFoot = 4,
RightFoot = 5,
CenterFeet = 7
}
public enum ParticleSupportType
{
Full,
Detect,
None
}
public static class Effects
{
private static ParticleSupportType m_ParticleSupportType = ParticleSupportType.Detect;
public static ParticleSupportType ParticleSupportType { get { return m_ParticleSupportType; } set { m_ParticleSupportType = value; } }
public static bool SendParticlesTo(NetState state)
{
return (m_ParticleSupportType == ParticleSupportType.Full ||
(m_ParticleSupportType == ParticleSupportType.Detect && (state.IsUOTDClient || state.IsEnhancedClient)));
}
public static void PlayExplodeSound(IPoint3D p, Map map)
{
PlaySound(p, map, Utility.RandomList(283, 284, 285, 286, 519, 773, 774, 775, 776, 777, 1231));
}
public static void PlaySound(IPoint3D p, Map map, int soundID)
{
if (soundID <= -1)
{
return;
}
if (map != null)
{
Packet playSound = null;
var 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, bool delay)
{
if (delay)
{
Timer.DelayCall(() => SendBoltEffect(e, sound, hue));
}
else
{
SendBoltEffect(e, sound, hue);
}
}
public static void SendBoltEffect(IEntity e, bool sound, int hue)
{
Map map = e.Map;
if (map == null)
{
return;
}
e.ProcessDelta();
Packet preEffect = null, postEffect = null, boltEffect = null, playSound = null;
var eable = map.GetClientsInRange(e.Location);
foreach (NetState state in eable)
{
if (state.Mobile.CanSee(e))
{
bool sendParticles = SendParticlesTo(state);
if (sendParticles)
{
if (preEffect == null)
{
preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0));
}
state.Send(preEffect);
}
if (boltEffect == null)
{
if (Core.SA && hue == 0)
{
boltEffect = Packet.Acquire(new BoltEffectNew(e));
}
else
{
boltEffect = Packet.Acquire(new BoltEffect(e, hue));
}
}
state.Send(boltEffect);
if (sendParticles)
{
if (postEffect == null)
{
postEffect = Packet.Acquire(new GraphicalEffect(EffectType.FixedFrom, e.Serial, Serial.Zero, 0, e.Location, e.Location, 0, 0, false, 0));
}
state.Send(postEffect);
}
if (sound)
{
if (playSound == null)
{
playSound = Packet.Acquire(new PlaySound(0x29, e));
}
state.Send(playSound);
}
}
}
Packet.Release(preEffect);
Packet.Release(postEffect);
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;
var 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)target).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)target).ProcessDelta();
}
Map map = target.Map;
if (map != null)
{
Packet particles = null, regular = null;
var 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)from).ProcessDelta();
}
if (to is Mobile)
{
((Mobile)to).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)from).ProcessDelta();
}
if (to is Mobile)
{
((Mobile)to).ProcessDelta();
}
Map map = from.Map;
if (map != null)
{
Packet particles = null, regular = null;
var 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)
{
var 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)
{
var eable = map.GetClientsInRange(new Point3D(origin));
p.Acquire();
foreach (NetState state in eable)
{
state.Mobile.ProcessDelta();
state.Send(p);
}
p.Release();
eable.Free();
}
}
}
}

50
Server/EventLog.cs Normal file
View File

@@ -0,0 +1,50 @@
#region References
using System;
using System.Diagnostics;
using DiagELog = System.Diagnostics.EventLog;
#endregion
namespace Server
{
public static class EventLog
{
static EventLog()
{
if (!DiagELog.SourceExists("ServUO"))
{
DiagELog.CreateEventSource("ServUO", "Application");
}
}
public static void Error(int eventID, string text)
{
DiagELog.WriteEntry("ServUO", text, EventLogEntryType.Error, eventID);
}
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("ServUO", text, EventLogEntryType.Warning, eventID);
}
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("ServUO", text, EventLogEntryType.Information, eventID);
}
public static void Inform(int eventID, string format, params object[] args)
{
Inform(eventID, String.Format(format, args));
}
}
}

2601
Server/EventSink.cs Normal file

File diff suppressed because it is too large Load Diff

358
Server/ExpansionInfo.cs Normal file
View File

@@ -0,0 +1,358 @@
#region References
using System;
#endregion
namespace Server
{
public enum Expansion
{
None = 0,
T2A,
UOR,
UOTD,
LBR,
AOS,
SE,
ML,
SA,
HS,
TOL,
EJ
}
public enum ThemePack
{
None = 0,
Kings,
Rustic,
Gothic
}
[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,
EJ = 0x00800000, // TODO: Verify value
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,
ExpansionEJ = ExpansionTOL | EJ
}
[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,
KR = 0x00000600, // uo:kr support flags
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,
ExpansionEJ = ExpansionTOL
}
[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,
EJ = 0x800000, // TODO: Verify value
HousingAOS = AOS,
HousingSE = HousingAOS | SE,
HousingML = HousingSE | ML | Crystal,
HousingSA = HousingML | SA | Gothic | Rustic,
HousingHS = HousingSA | HS,
HousingTOL = HousingHS | TOL | Jungle | Shadowguard,
HousingEJ = HousingTOL | EJ
}
public class ExpansionInfo
{
public static ExpansionInfo CoreExpansion { get { return GetInfo(Core.Expansion); } }
public static ExpansionInfo[] Table { get; private set; }
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),
new ExpansionInfo(
11,
"Endless Journey",
new ClientVersion("7.0.61.0"),
FeatureFlags.ExpansionEJ,
CharacterListFlags.ExpansionEJ,
HousingFlags.HousingEJ)
};
}
public static FeatureFlags GetFeatures(Expansion ex)
{
var info = GetInfo(ex);
if (info != null)
{
return info.SupportedFeatures;
}
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;
case Expansion.EJ:
return FeatureFlags.ExpansionEJ;
}
return FeatureFlags.ExpansionNone;
}
public static ExpansionInfo GetInfo(Expansion ex)
{
return GetInfo((int)ex);
}
public static ExpansionInfo GetInfo(int ex)
{
var v = ex;
if (v < 0 || v >= Table.Length)
{
v = 0;
}
return Table[v];
}
public int ID { get; private set; }
public string Name { get; set; }
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; }
public ExpansionInfo(
int id,
string name,
ClientFlags clientFlags,
FeatureFlags supportedFeatures,
CharacterListFlags charListFlags,
HousingFlags customHousingFlag)
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
{
ClientFlags = clientFlags;
}
public ExpansionInfo(
int id,
string name,
ClientVersion requiredClient,
FeatureFlags supportedFeatures,
CharacterListFlags charListFlags,
HousingFlags customHousingFlag)
: this(id, name, supportedFeatures, charListFlags, customHousingFlag)
{
RequiredClient = requiredClient;
}
private ExpansionInfo(
int id,
string name,
FeatureFlags supportedFeatures,
CharacterListFlags charListFlags,
HousingFlags customHousingFlag)
{
ID = id;
Name = name;
SupportedFeatures = supportedFeatures;
CharacterListFlags = charListFlags;
CustomHousingFlag = customHousingFlag;
}
public override string ToString()
{
return Name;
}
}
}

604
Server/Geometry.cs Normal file
View File

@@ -0,0 +1,604 @@
#region References
using System;
#endregion
namespace Server
{
[Parsable]
public struct Point2D : IPoint2D, IComparable, IComparable<Point2D>
{
internal int m_X;
internal int m_Y;
public static readonly Point2D Zero = new Point2D(0, 0);
public Point2D(int x, int y)
{
m_X = x;
m_Y = y;
}
public Point2D(IPoint2D p)
: this(p.X, p.Y)
{ }
[CommandProperty(AccessLevel.Counselor)]
public int X { get { return m_X; } set { m_X = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Y { get { return m_Y; } set { m_Y = value; } }
public override string ToString()
{
return String.Format("({0}, {1})", m_X, m_Y);
}
public static Point2D Parse(string value)
{
int start = value.IndexOf('(');
int end = value.IndexOf(',', start + 1);
string param1 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(')', start + 1);
string param2 = value.Substring(start + 1, end - (start + 1)).Trim();
return new Point2D(Convert.ToInt32(param1), Convert.ToInt32(param2));
}
public int CompareTo(Point2D other)
{
int v = (m_X.CompareTo(other.m_X));
if (v == 0)
{
v = (m_Y.CompareTo(other.m_Y));
}
return v;
}
public int CompareTo(object other)
{
if (other is Point2D)
{
return CompareTo((Point2D)other);
}
if (other == null)
{
return -1;
}
throw new ArgumentException();
}
public override bool Equals(object o)
{
if (!(o is IPoint2D))
{
return false;
}
IPoint2D p = (IPoint2D)o;
return m_X == p.X && m_Y == p.Y;
}
public override int GetHashCode()
{
unchecked
{
var hash = 1 + Math.Abs(X) + Math.Abs(Y);
hash = (hash * 397) ^ X;
hash = (hash * 397) ^ Y;
return hash;
}
}
public static bool operator ==(Point2D l, Point2D r)
{
return l.m_X == r.m_X && l.m_Y == r.m_Y;
}
public static bool operator !=(Point2D l, Point2D r)
{
return l.m_X != r.m_X || l.m_Y != r.m_Y;
}
public static bool operator ==(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X == r.X && l.m_Y == r.Y;
}
public static bool operator !=(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X != r.X || l.m_Y != r.Y;
}
public static bool operator >(Point2D l, Point2D r)
{
return l.m_X > r.m_X && l.m_Y > r.m_Y;
}
public static bool operator >(Point2D l, Point3D r)
{
return l.m_X > r.m_X && l.m_Y > r.m_Y;
}
public static bool operator >(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X > r.X && l.m_Y > r.Y;
}
public static bool operator <(Point2D l, Point2D r)
{
return l.m_X < r.m_X && l.m_Y < r.m_Y;
}
public static bool operator <(Point2D l, Point3D r)
{
return l.m_X < r.m_X && l.m_Y < r.m_Y;
}
public static bool operator <(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X < r.X && l.m_Y < r.Y;
}
public static bool operator >=(Point2D l, Point2D r)
{
return l.m_X >= r.m_X && l.m_Y >= r.m_Y;
}
public static bool operator >=(Point2D l, Point3D r)
{
return l.m_X >= r.m_X && l.m_Y >= r.m_Y;
}
public static bool operator >=(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X >= r.X && l.m_Y >= r.Y;
}
public static bool operator <=(Point2D l, Point2D r)
{
return l.m_X <= r.m_X && l.m_Y <= r.m_Y;
}
public static bool operator <=(Point2D l, Point3D r)
{
return l.m_X <= r.m_X && l.m_Y <= r.m_Y;
}
public static bool operator <=(Point2D l, IPoint2D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X <= r.X && l.m_Y <= r.Y;
}
}
[Parsable]
public struct Point3D : IPoint3D, IComparable, IComparable<Point3D>
{
internal int m_X;
internal int m_Y;
internal int m_Z;
public static readonly Point3D Zero = new Point3D(0, 0, 0);
public Point3D(int x, int y, int z)
{
m_X = x;
m_Y = y;
m_Z = z;
}
public Point3D(IPoint3D p)
: this(p.X, p.Y, p.Z)
{ }
public Point3D(IPoint2D p, int z)
: this(p.X, p.Y, z)
{ }
[CommandProperty(AccessLevel.Counselor)]
public int X { get { return m_X; } set { m_X = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Y { get { return m_Y; } set { m_Y = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Z { get { return m_Z; } set { m_Z = value; } }
public override string ToString()
{
return String.Format("({0}, {1}, {2})", m_X, m_Y, m_Z);
}
public override bool Equals(object o)
{
if (!(o is IPoint3D))
{
return false;
}
IPoint3D p = (IPoint3D)o;
return m_X == p.X && m_Y == p.Y && m_Z == p.Z;
}
public override int GetHashCode()
{
unchecked
{
var hash = 1 + Math.Abs(X) + Math.Abs(Y) + Math.Abs(Z);
hash = (hash * 397) ^ X;
hash = (hash * 397) ^ Y;
hash = (hash * 397) ^ Z;
return hash;
}
}
public static Point3D Parse(string value)
{
int start = value.IndexOf('(');
int end = value.IndexOf(',', start + 1);
string param1 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param2 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(')', start + 1);
string param3 = value.Substring(start + 1, end - (start + 1)).Trim();
return new Point3D(Convert.ToInt32(param1), Convert.ToInt32(param2), Convert.ToInt32(param3));
}
public static bool operator ==(Point3D l, Point3D r)
{
return l.m_X == r.m_X && l.m_Y == r.m_Y && l.m_Z == r.m_Z;
}
public static bool operator !=(Point3D l, Point3D r)
{
return l.m_X != r.m_X || l.m_Y != r.m_Y || l.m_Z != r.m_Z;
}
public static bool operator ==(Point3D l, IPoint3D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;
}
public static bool operator !=(Point3D l, IPoint3D r)
{
if (ReferenceEquals(r, null))
{
return false;
}
return l.m_X != r.X || l.m_Y != r.Y || l.m_Z != r.Z;
}
public int CompareTo(Point3D other)
{
int v = (m_X.CompareTo(other.m_X));
if (v == 0)
{
v = (m_Y.CompareTo(other.m_Y));
if (v == 0)
{
v = (m_Z.CompareTo(other.m_Z));
}
}
return v;
}
public int CompareTo(object other)
{
if (other is Point3D)
{
return CompareTo((Point3D)other);
}
if (other == null)
{
return -1;
}
throw new ArgumentException();
}
}
[NoSort]
[Parsable]
[PropertyObject]
public struct Rectangle2D
{
private Point2D m_Start;
private Point2D m_End;
public Rectangle2D(IPoint2D start, IPoint2D end)
{
m_Start = new Point2D(start);
m_End = new Point2D(end);
}
public Rectangle2D(int x, int y, int width, int height)
{
m_Start = new Point2D(x, y);
m_End = new Point2D(x + width, y + height);
}
public void Set(int x, int y, int width, int height)
{
m_Start = new Point2D(x, y);
m_End = new Point2D(x + width, y + height);
}
public static Rectangle2D Parse(string value)
{
int start = value.IndexOf('(');
int end = value.IndexOf(',', start + 1);
string param1 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param2 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param3 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(')', start + 1);
string param4 = value.Substring(start + 1, end - (start + 1)).Trim();
return new Rectangle2D(
Convert.ToInt32(param1),
Convert.ToInt32(param2),
Convert.ToInt32(param3),
Convert.ToInt32(param4));
}
[CommandProperty(AccessLevel.Counselor)]
public Point2D Start { get { return m_Start; } set { m_Start = value; } }
[CommandProperty(AccessLevel.Counselor)]
public Point2D End { get { return m_End; } set { m_End = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int X { get { return m_Start.m_X; } set { m_Start.m_X = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Y { get { return m_Start.m_Y; } set { m_Start.m_Y = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Width { get { return m_End.m_X - m_Start.m_X; } set { m_End.m_X = m_Start.m_X + value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Height { get { return m_End.m_Y - m_Start.m_Y; } set { m_End.m_Y = m_Start.m_Y + value; } }
public void MakeHold(Rectangle2D r)
{
if (r.m_Start.m_X < m_Start.m_X)
{
m_Start.m_X = r.m_Start.m_X;
}
if (r.m_Start.m_Y < m_Start.m_Y)
{
m_Start.m_Y = r.m_Start.m_Y;
}
if (r.m_End.m_X > m_End.m_X)
{
m_End.m_X = r.m_End.m_X;
}
if (r.m_End.m_Y > m_End.m_Y)
{
m_End.m_Y = r.m_End.m_Y;
}
}
public bool Contains(Point3D p)
{
return (m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y);
//return ( m_Start <= p && m_End > p );
}
public bool Contains(Point2D p)
{
return (m_Start.m_X <= p.m_X && m_Start.m_Y <= p.m_Y && m_End.m_X > p.m_X && m_End.m_Y > p.m_Y);
//return ( m_Start <= p && m_End > p );
}
public bool Contains(IPoint2D p)
{
return (m_Start <= p && m_End > p);
}
public override string ToString()
{
return String.Format("({0}, {1})+({2}, {3})", X, Y, Width, Height);
}
public override int GetHashCode()
{
unchecked
{
var hash = 1 + Math.Abs(Start.X + Start.Y) + Math.Abs(End.X + End.Y);
hash = (hash * 397) ^ Start.GetHashCode();
hash = (hash * 397) ^ End.GetHashCode();
return hash;
}
}
}
[NoSort]
[PropertyObject]
public struct Rectangle3D
{
private Point3D m_Start;
private Point3D m_End;
public Rectangle3D(Point3D start, Point3D end)
{
m_Start = start;
m_End = end;
}
public Rectangle3D(int x, int y, int z, int width, int height, int depth)
{
m_Start = new Point3D(x, y, z);
m_End = new Point3D(x + width, y + height, z + depth);
}
public void Set(int x, int y, int z, int width, int height, int depth)
{
m_Start = new Point3D(x, y, z);
m_End = new Point3D(x + width, y + height, z + depth);
}
public static Rectangle3D Parse(string value)
{
int start = value.IndexOf('(');
int end = value.IndexOf(',', start + 1);
string param1 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param2 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param3 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param4 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(',', start + 1);
string param5 = value.Substring(start + 1, end - (start + 1)).Trim();
start = end;
end = value.IndexOf(')', start + 1);
string param6 = value.Substring(start + 1, end - (start + 1)).Trim();
return new Rectangle3D(
Convert.ToInt32(param1),
Convert.ToInt32(param2),
Convert.ToInt32(param3),
Convert.ToInt32(param4),
Convert.ToInt32(param5),
Convert.ToInt32(param6));
}
[CommandProperty(AccessLevel.Counselor)]
public Point3D Start { get { return m_Start; } set { m_Start = value; } }
[CommandProperty(AccessLevel.Counselor)]
public Point3D End { get { return m_End; } set { m_End = value; } }
[CommandProperty(AccessLevel.Counselor)]
public int Width { get { return m_End.X - m_Start.X; } }
[CommandProperty(AccessLevel.Counselor)]
public int Height { get { return m_End.Y - m_Start.Y; } }
[CommandProperty(AccessLevel.Counselor)]
public int Depth { get { return m_End.Z - m_Start.Z; } }
public bool Contains(Point3D p)
{
return (p.m_X >= m_Start.m_X) && (p.m_X < m_End.m_X) && (p.m_Y >= m_Start.m_Y) && (p.m_Y < m_End.m_Y) &&
(p.m_Z >= m_Start.m_Z) && (p.m_Z < m_End.m_Z);
}
public bool Contains(IPoint3D p)
{
return (p.X >= m_Start.m_X) && (p.X < m_End.m_X) && (p.Y >= m_Start.m_Y) && (p.Y < m_End.m_Y) && (p.Z >= m_Start.m_Z) &&
(p.Z < m_End.m_Z);
}
public override string ToString()
{
return String.Format("({0}, {1}, {2})+({3}, {4}, {5})", Start.X, Start.Y, Start.Z, Width, Height, Depth);
}
public override int GetHashCode()
{
unchecked
{
var hash = 1 + Math.Abs(Start.X + Start.Y + Start.Z) + Math.Abs(End.X + End.Y + End.Z);
hash = (hash * 397) ^ Start.GetHashCode();
hash = (hash * 397) ^ End.GetHashCode();
return hash;
}
}
}
}

123
Server/Guild.cs Normal file
View File

@@ -0,0 +1,123 @@
#region References
using System;
using System.Collections.Generic;
#endregion
namespace Server.Guilds
{
public enum GuildType
{
Regular,
Chaos,
Order
}
public abstract class BaseGuild : ISerializable
{
private readonly int m_Id;
protected BaseGuild(int Id) //serialization ctor
{
m_Id = Id;
m_GuildList.Add(m_Id, this);
if (m_Id + 1 > m_NextID)
{
m_NextID = m_Id + 1;
}
}
protected BaseGuild()
{
m_Id = m_NextID++;
m_GuildList.Add(m_Id, this);
}
[CommandProperty(AccessLevel.Counselor)]
public int Id { get { return m_Id; } }
int ISerializable.TypeReference { get { return 0; } }
int ISerializable.SerialIdentity { get { return m_Id; } }
public abstract void Deserialize(GenericReader reader);
public abstract void Serialize(GenericWriter writer);
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);
private static readonly Dictionary<int, BaseGuild> m_GuildList = new Dictionary<int, BaseGuild>();
private static int m_NextID = 1;
public static Dictionary<int, BaseGuild> List { get { return m_GuildList; } }
public static BaseGuild Find(int id)
{
BaseGuild g;
m_GuildList.TryGetValue(id, out g);
return g;
}
public static BaseGuild FindByName(string name)
{
foreach (BaseGuild g in m_GuildList.Values)
{
if (g.Name == name)
{
return g;
}
}
return null;
}
public static BaseGuild FindByAbbrev(string abbr)
{
foreach (BaseGuild g in m_GuildList.Values)
{
if (g.Abbreviation == abbr)
{
return g;
}
}
return null;
}
public static List<BaseGuild> Search(string find)
{
var words = find.ToLower().Split(' ');
var results = new List<BaseGuild>();
foreach (BaseGuild g in m_GuildList.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);
}
}
return results;
}
public override string ToString()
{
return String.Format("0x{0:X} \"{1} [{2}]\"", m_Id, Name, Abbreviation);
}
}
}

View File

@@ -0,0 +1,24 @@
using System;
using Server.Network;
namespace Server.Gumps
{
public class ECHandleInput : GumpEntry
{
public ECHandleInput()
{
}
public override string Compile()
{
return String.Format("{{ echandleinput }}");
}
private static byte[] m_LayoutName = Gump.StringToBuffer("echandleinput");
public override void AppendTo(IGumpWriter disp)
{
disp.AppendLayout(m_LayoutName);
}
}
}

493
Server/Gumps/Gump.cs Normal file
View File

@@ -0,0 +1,493 @@
#region References
using System;
using System.Collections.Generic;
using System.Text;
using Server.Network;
#endregion
namespace Server.Gumps
{
public class Gump
{
private List<GumpEntry> m_Entries;
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 virtual int GetTypeID()
{
return this.GetType().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();
m_Entries = new List<GumpEntry>();
m_Strings = new List<string>();
}
public void Invalidate()
{
//if ( m_Strings.Count > 0 )
// m_Strings.Clear();
}
public int TypeID { get; set; }
public List<GumpEntry> Entries { get { return m_Entries; } }
public int Serial
{
get { return m_Serial; }
set
{
if (m_Serial != value)
{
m_Serial = value;
Invalidate();
}
}
}
public int X
{
get { return m_X; }
set
{
if (m_X != value)
{
m_X = value;
Invalidate();
}
}
}
public int Y
{
get { return m_Y; }
set
{
if (m_Y != value)
{
m_Y = value;
Invalidate();
}
}
}
public bool Disposable
{
get { return m_Disposable; }
set
{
if (m_Disposable != value)
{
m_Disposable = value;
Invalidate();
}
}
}
public bool Resizable
{
get { return m_Resizable; }
set
{
if (m_Resizable != value)
{
m_Resizable = value;
Invalidate();
}
}
}
public bool Dragable
{
get { return m_Dragable; }
set
{
if (m_Dragable != value)
{
m_Dragable = value;
Invalidate();
}
}
}
public bool Closable
{
get { return 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 AddHtmlIntern(int x, int y, int width, int height, int textid, bool background, bool scrollbar)
{
Add(new GumpHtml(x, y, width, height, textid, 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 AddSpriteImage(int x, int y, int gumpID, int width, int height, int sx, int sy)
{
Add(new GumpSpriteImage(x, y, gumpID, width, height, sx, sy));
}
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 AddLabelIntern(int x, int y, int hue, int textid)
{
Add(new GumpLabel(x, y, hue, textid));
}
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 AddLabelCroppedIntern(int x, int y, int width, int height, int hue, int textid)
{
Add(new GumpLabelCropped(x, y, width, height, hue, textid));
}
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 AddTextEntryIntern(int x, int y, int width, int height, int hue, int entryID, int initialTextID)
{
Add(new GumpTextEntry(x, y, width, height, hue, entryID, initialTextID));
}
/*public void AddTooltip(int number, string args)
{
Add(new GumpTooltip(number, args));
}*/
public void AddItemProperty(Item item)
{
Add(new GumpItemProperty(item.Serial.Value));
}
public void AddItemProperty(int serial)
{
Add(new GumpItemProperty(serial));
}
public void AddECHandleInput()
{
Add(new ECHandleInput());
}
public void Add(GumpEntry g)
{
if (g.Parent != this)
{
g.Parent = this;
}
else if (!m_Entries.Contains(g))
{
Invalidate();
m_Entries.Add(g);
}
}
public void Remove(GumpEntry g)
{
if (g == null || !m_Entries.Contains(g))
{
return;
}
Invalidate();
m_Entries.Remove(g);
g.Parent = null;
}
public int Intern(string value)
{
return Intern(value, false);
}
public int Intern(string value, bool enforceUnique)
{
if (enforceUnique)
{
int indexOf = m_Strings.IndexOf(value);
if (indexOf >= 0)
return indexOf;
}
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 readonly byte[] m_BeginLayout = StringToBuffer("{ ");
private static readonly byte[] m_EndLayout = StringToBuffer(" }");
private static readonly byte[] m_NoMove = StringToBuffer("{ nomove }");
private static readonly byte[] m_NoClose = StringToBuffer("{ noclose }");
private static readonly byte[] m_NoDispose = StringToBuffer("{ nodispose }");
private static readonly byte[] m_NoResize = StringToBuffer("{ noresize }");
protected virtual Packet GetPacketFor(NetState ns)
{
return Compile(ns);
}
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);
}
var count = m_Entries.Count;
GumpEntry e;
for (var i = 0; i < count; ++i)
{
e = m_Entries[i];
disp.AppendLayout(m_BeginLayout);
e.AppendTo(disp);
disp.AppendLayout(m_EndLayout);
}
disp.WriteStrings(m_Strings);
disp.Flush();
m_TextEntries = disp.TextEntries;
m_Switches = disp.Switches;
return (Packet)disp;
}
public virtual void OnResponse(NetState sender, RelayInfo info)
{ }
public virtual void OnServerClose(NetState owner)
{ }
}
}

View File

@@ -0,0 +1,103 @@
/***************************************************************************
* GumpAlphaRegion.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpAlphaRegion : GumpEntry
{
private int m_X, m_Y;
private int m_Width, m_Height;
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public GumpAlphaRegion( int x, int y, int width, int height )
{
m_X = x;
m_Y = y;
m_Width = width;
m_Height = height;
}
public override string Compile()
{
return String.Format( "{{ checkertrans {0} {1} {2} {3} }}", m_X, m_Y, m_Width, m_Height );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "checkertrans" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_X );
disp.AppendLayout( m_Y );
disp.AppendLayout( m_Width );
disp.AppendLayout( m_Height );
}
}
}

View File

@@ -0,0 +1,118 @@
/***************************************************************************
* GumpBackground.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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 int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int GumpID
{
get
{
return m_GumpID;
}
set
{
Delta( ref m_GumpID, 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 override string Compile()
{
return String.Format( "{{ resizepic {0} {1} {2} {3} {4} }}", m_X, m_Y, m_GumpID, m_Width, m_Height );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "resizepic" );
public override void AppendTo( 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 );
}
}
}

164
Server/Gumps/GumpButton.cs Normal file
View File

@@ -0,0 +1,164 @@
/***************************************************************************
* GumpButton.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
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 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
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int NormalID
{
get
{
return m_ID1;
}
set
{
Delta( ref m_ID1, value );
}
}
public int PressedID
{
get
{
return m_ID2;
}
set
{
Delta( ref m_ID2, value );
}
}
public int ButtonID
{
get
{
return m_ButtonID;
}
set
{
Delta( ref m_ButtonID, value );
}
}
public GumpButtonType Type
{
get
{
return m_Type;
}
set
{
if ( m_Type != value )
{
m_Type = value;
Gump parent = Parent;
if ( parent != null )
{
parent.Invalidate();
}
}
}
}
public int Param
{
get
{
return m_Param;
}
set
{
Delta( ref m_Param, value );
}
}
public override string Compile()
{
return String.Format( "{{ button {0} {1} {2} {3} {4} {5} {6} }}", 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( 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 );
}
}
}

135
Server/Gumps/GumpCheck.cs Normal file
View File

@@ -0,0 +1,135 @@
/***************************************************************************
* GumpCheck.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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 int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int InactiveID
{
get
{
return m_ID1;
}
set
{
Delta( ref m_ID1, value );
}
}
public int ActiveID
{
get
{
return m_ID2;
}
set
{
Delta( ref m_ID2, value );
}
}
public bool InitialState
{
get
{
return m_InitialState;
}
set
{
Delta( ref m_InitialState, value );
}
}
public int SwitchID
{
get
{
return m_SwitchID;
}
set
{
Delta( ref m_SwitchID, 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 override string Compile()
{
return String.Format( "{{ checkbox {0} {1} {2} {3} {4} {5} }}", 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( 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++;
}
}
}

83
Server/Gumps/GumpEntry.cs Normal file
View File

@@ -0,0 +1,83 @@
#region References
using Server.Network;
#endregion
namespace Server.Gumps
{
public abstract class GumpEntry
{
private Gump _Parent;
public Gump Parent
{
get { return _Parent; }
set
{
if (_Parent == value)
{
return;
}
if (_Parent != null)
{
_Parent.Remove(this);
}
_Parent = value;
if (_Parent != null)
{
_Parent.Add(this);
}
}
}
protected void Delta(ref int var, int val)
{
if (var == val)
{
return;
}
var = val;
if (_Parent != null)
{
_Parent.Invalidate();
}
}
protected void Delta(ref bool var, bool val)
{
if (var == val)
{
return;
}
var = val;
if (_Parent != null)
{
_Parent.Invalidate();
}
}
protected void Delta(ref string var, string val)
{
if (var == val)
{
return;
}
var = val;
if (_Parent != null)
{
_Parent.Invalidate();
}
}
public abstract string Compile();
public abstract void AppendTo(IGumpWriter disp);
}
}

60
Server/Gumps/GumpGroup.cs Normal file
View File

@@ -0,0 +1,60 @@
/***************************************************************************
* GumpGroup.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpGroup : GumpEntry
{
private int m_Group;
public GumpGroup( int group )
{
m_Group = group;
}
public int Group
{
get
{
return m_Group;
}
set
{
Delta( ref m_Group, value );
}
}
public override string Compile()
{
return String.Format( "{{ group {0} }}", m_Group );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "group" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_Group );
}
}
}

159
Server/Gumps/GumpHtml.cs Normal file
View File

@@ -0,0 +1,159 @@
/***************************************************************************
* GumpHtml.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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 readonly int m_TextID;
private bool m_Background, m_Scrollbar;
public int X
{
get
{
return m_X;
}
set
{
Delta(ref m_X, value);
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta(ref m_Y, value);
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta(ref m_Width, value);
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta(ref m_Height, value);
}
}
public string Text
{
get
{
return m_Text;
}
set
{
Delta(ref m_Text, value);
}
}
public bool Background
{
get
{
return m_Background;
}
set
{
Delta(ref m_Background, value);
}
}
public bool Scrollbar
{
get
{
return m_Scrollbar;
}
set
{
Delta(ref m_Scrollbar, 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 GumpHtml(int x, int y, int width, int height, int textid, bool background, bool scrollbar)
{
m_X = x;
m_Y = y;
m_Width = width;
m_Height = height;
m_TextID = textid;
m_Background = background;
m_Scrollbar = scrollbar;
}
public override string Compile()
{
return String.Format("{{ htmlgump {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, m_Text == null ? m_TextID : Parent.Intern(m_Text), m_Background ? 1 : 0, m_Scrollbar ? 1 : 0);
}
private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump");
public override void AppendTo(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_Text == null ? m_TextID : Parent.Intern(m_Text));
disp.AppendLayout(m_Background);
disp.AppendLayout(m_Scrollbar);
}
}
}

View File

@@ -0,0 +1,287 @@
/***************************************************************************
* GumpHtmlLocalized.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
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;
private GumpHtmlLocalizedType m_Type;
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int Number
{
get
{
return m_Number;
}
set
{
Delta( ref m_Number, value );
}
}
public string Args
{
get
{
return m_Args;
}
set
{
Delta( ref m_Args, value );
}
}
public int Color
{
get
{
return m_Color;
}
set
{
Delta( ref m_Color, value );
}
}
public bool Background
{
get
{
return m_Background;
}
set
{
Delta( ref m_Background, value );
}
}
public bool Scrollbar
{
get
{
return m_Scrollbar;
}
set
{
Delta( ref m_Scrollbar, value );
}
}
public GumpHtmlLocalizedType Type
{
get
{
return m_Type;
}
set
{
if ( m_Type != value )
{
m_Type = value;
if ( Parent != null )
Parent.Invalidate();
}
}
}
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;
m_Type = GumpHtmlLocalizedType.Plain;
}
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;
m_Type = GumpHtmlLocalizedType.Color;
}
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?
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;
m_Type = GumpHtmlLocalizedType.Args;
}
public override string Compile()
{
switch ( m_Type )
{
case GumpHtmlLocalizedType.Plain:
return String.Format( "{{ xmfhtmlgump {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, m_Number, m_Background ? 1 : 0, m_Scrollbar ? 1 : 0 );
case GumpHtmlLocalizedType.Color:
return String.Format( "{{ xmfhtmlgumpcolor {0} {1} {2} {3} {4} {5} {6} {7} }}", m_X, m_Y, m_Width, m_Height, m_Number, m_Background ? 1 : 0, m_Scrollbar ? 1 : 0, m_Color );
default: // GumpHtmlLocalizedType.Args
return String.Format( "{{ xmfhtmltok {0} {1} {2} {3} {4} {5} {6} {7} @{8}@ }}", 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( 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 );
break;
}
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 );
break;
}
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 );
break;
}
}
}
}
}

117
Server/Gumps/GumpImage.cs Normal file
View File

@@ -0,0 +1,117 @@
/***************************************************************************
* GumpImage.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpImage : GumpEntry
{
private int m_X, m_Y;
private int m_GumpID;
private int m_Hue;
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 int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int GumpID
{
get
{
return m_GumpID;
}
set
{
Delta( ref m_GumpID, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public override string Compile()
{
if ( m_Hue == 0 )
return String.Format( "{{ gumppic {0} {1} {2} }}", m_X, m_Y, m_GumpID );
else
return String.Format( "{{ gumppic {0} {1} {2} hue={3} }}", m_X, m_Y, m_GumpID, m_Hue );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppic" );
private static byte[] m_HueEquals = Gump.StringToBuffer( " hue=" );
public override void AppendTo( 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 );
}
}
}
}

View File

@@ -0,0 +1,252 @@
/***************************************************************************
* GumpImageTileButton.cs
* -------------------
* begin : April 26, 2005
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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;
private int m_ItemID;
private int m_Hue;
private int m_Width;
private int m_Height;
private int m_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 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;
m_ItemID = itemID;
m_Hue = hue;
m_Width = width;
m_Height = height;
m_LocalizedTooltip = localizedTooltip;
}
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int NormalID
{
get
{
return m_ID1;
}
set
{
Delta( ref m_ID1, value );
}
}
public int PressedID
{
get
{
return m_ID2;
}
set
{
Delta( ref m_ID2, value );
}
}
public int ButtonID
{
get
{
return m_ButtonID;
}
set
{
Delta( ref m_ButtonID, value );
}
}
public GumpButtonType Type
{
get
{
return m_Type;
}
set
{
if( m_Type != value )
{
m_Type = value;
Gump parent = Parent;
if( parent != null )
{
parent.Invalidate();
}
}
}
}
public int Param
{
get
{
return m_Param;
}
set
{
Delta( ref m_Param, value );
}
}
public int ItemID
{
get
{
return m_ItemID;
}
set
{
Delta( ref m_ItemID, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int LocalizedTooltip
{
get
{
return m_LocalizedTooltip;
}
set
{
m_LocalizedTooltip = value;
}
}
public override string Compile()
{
if( m_LocalizedTooltip > 0 )
return String.Format( "{{ buttontileart {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} }}{{ tooltip {11} }}", m_X, m_Y, m_ID1, m_ID2, (int)m_Type, m_Param, m_ButtonID, m_ItemID, m_Hue, m_Width, m_Height, m_LocalizedTooltip );
else
return String.Format( "{{ buttontileart {0} {1} {2} {3} {4} {5} {6} {7} {8} {9} {10} }}", m_X, m_Y, m_ID1, m_ID2, (int)m_Type, m_Param, m_ButtonID, m_ItemID, m_Hue, m_Width, m_Height );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "buttontileart" );
private static byte[] m_LayoutTooltip = Gump.StringToBuffer( " }{ tooltip" );
public override void AppendTo( 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( m_LocalizedTooltip > 0 )
{
disp.AppendLayout( m_LayoutTooltip );
disp.AppendLayout( m_LocalizedTooltip );
}
}
}
}

View File

@@ -0,0 +1,118 @@
/***************************************************************************
* GumpImageTiled.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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 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
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int GumpID
{
get
{
return m_GumpID;
}
set
{
Delta( ref m_GumpID, value );
}
}
public override string Compile()
{
return String.Format( "{{ gumppictiled {0} {1} {2} {3} {4} }}", m_X, m_Y, m_Width, m_Height, m_GumpID );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "gumppictiled" );
public override void AppendTo( 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 );
}
}
}

114
Server/Gumps/GumpItem.cs Normal file
View File

@@ -0,0 +1,114 @@
/***************************************************************************
* GumpItem.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpItem : GumpEntry
{
private int m_X, m_Y;
private int m_ItemID;
private int m_Hue;
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 int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int ItemID
{
get
{
return m_ItemID;
}
set
{
Delta( ref m_ItemID, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public override string Compile()
{
if ( m_Hue == 0 )
return String.Format( "{{ tilepic {0} {1} {2} }}", m_X, m_Y, m_ItemID );
else
return String.Format( "{{ tilepichue {0} {1} {2} {3} }}", 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( 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 );
}
}
}

View File

@@ -0,0 +1,60 @@
/***************************************************************************
* GumpItemProperty.cs
* -------------------
* begin : May 26, 2013
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpItemProperty : GumpEntry
{
private int m_Serial;
public GumpItemProperty( int serial )
{
m_Serial = serial;
}
public int Serial
{
get
{
return m_Serial;
}
set
{
Delta( ref m_Serial, value );
}
}
public override string Compile()
{
return String.Format( "{{ itemproperty {0} }}", m_Serial );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "itemproperty" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_Serial );
}
}
}

113
Server/Gumps/GumpLabel.cs Normal file
View File

@@ -0,0 +1,113 @@
/***************************************************************************
* GumpLabel.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpLabel : GumpEntry
{
private int m_X, m_Y;
private int m_Hue;
private string m_Text;
private int m_TextID;
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, int textid)
{
m_X = x;
m_Y = y;
m_Hue = hue;
m_TextID = textid;
}
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public string Text
{
get
{
return m_Text;
}
set
{
Delta( ref m_Text, value );
}
}
public override string Compile()
{
return String.Format( "{{ text {0} {1} {2} {3} }}", m_X, m_Y, m_Hue, m_Text == null ? m_TextID : Parent.Intern(m_Text));
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "text" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_X );
disp.AppendLayout( m_Y );
disp.AppendLayout( m_Hue );
disp.AppendLayout(m_Text == null ? m_TextID : Parent.Intern(m_Text));
}
}
}

View File

@@ -0,0 +1,144 @@
/***************************************************************************
* GumpLabelCropped.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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;
private int m_TextID;
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public string Text
{
get
{
return m_Text;
}
set
{
Delta( ref m_Text, 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 GumpLabelCropped(int x, int y, int width, int height, int hue, int textid)
{
m_X = x;
m_Y = y;
m_Width = width;
m_Height = height;
m_Hue = hue;
m_TextID = textid;
}
public override string Compile()
{
return String.Format( "{{ croppedtext {0} {1} {2} {3} {4} {5} }}", m_X, m_Y, m_Width, m_Height, m_Hue, m_Text == null ? m_TextID : Parent.Intern(m_Text));
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "croppedtext" );
public override void AppendTo( 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_Text == null ? m_TextID : Parent.Intern(m_Text) );
}
}
}

60
Server/Gumps/GumpPage.cs Normal file
View File

@@ -0,0 +1,60 @@
/***************************************************************************
* GumpPage.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpPage : GumpEntry
{
private int m_Page;
public GumpPage( int page )
{
m_Page = page;
}
public int Page
{
get
{
return m_Page;
}
set
{
Delta( ref m_Page, value );
}
}
public override string Compile()
{
return String.Format( "{{ page {0} }}", m_Page );
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "page" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_Page );
}
}
}

135
Server/Gumps/GumpRadio.cs Normal file
View File

@@ -0,0 +1,135 @@
/***************************************************************************
* GumpRadio.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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 int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int InactiveID
{
get
{
return m_ID1;
}
set
{
Delta( ref m_ID1, value );
}
}
public int ActiveID
{
get
{
return m_ID2;
}
set
{
Delta( ref m_ID2, value );
}
}
public bool InitialState
{
get
{
return m_InitialState;
}
set
{
Delta( ref m_InitialState, value );
}
}
public int SwitchID
{
get
{
return m_SwitchID;
}
set
{
Delta( ref m_SwitchID, 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 override string Compile()
{
return String.Format( "{{ radio {0} {1} {2} {3} {4} {5} }}", 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( 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++;
}
}
}

View File

@@ -0,0 +1,126 @@
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpSpriteImage : GumpEntry
{
private int m_X, m_Y, m_SX, m_SY;
private int m_Width, m_Height;
private int m_GumpID;
public GumpSpriteImage(int x, int y, int gumpID, int width, int height, int sx, int sy)
{
m_X = x;
m_Y = y;
m_GumpID = gumpID;
m_Width = width;
m_Height = height;
m_SX = sx;
m_SY = sy;
}
public int X
{
get
{
return m_X;
}
set
{
Delta(ref m_X, value);
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta(ref m_Y, value);
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta(ref m_Width, value);
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta(ref m_Height, value);
}
}
public int GumpID
{
get
{
return m_GumpID;
}
set
{
Delta(ref m_GumpID, value);
}
}
public int SX
{
get
{
return m_SX;
}
set
{
Delta(ref m_SX, value);
}
}
public int SY
{
get
{
return m_SY;
}
set
{
Delta(ref m_SY, value);
}
}
public override string Compile()
{
return String.Format("{{ picinpic {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_GumpID, m_Width, m_Height, m_SX, m_SY);
}
private static byte[] m_LayoutName = Gump.StringToBuffer("picinpic");
public override void AppendTo(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);
disp.AppendLayout(m_SX);
disp.AppendLayout(m_SY);
}
}
}

View File

@@ -0,0 +1,162 @@
/***************************************************************************
* GumpTextEntry.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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;
private int m_InitialTextID = -1;
public int X
{
get
{
return m_X;
}
set
{
Delta( ref m_X, value );
}
}
public int Y
{
get
{
return m_Y;
}
set
{
Delta( ref m_Y, value );
}
}
public int Width
{
get
{
return m_Width;
}
set
{
Delta( ref m_Width, value );
}
}
public int Height
{
get
{
return m_Height;
}
set
{
Delta( ref m_Height, value );
}
}
public int Hue
{
get
{
return m_Hue;
}
set
{
Delta( ref m_Hue, value );
}
}
public int EntryID
{
get
{
return m_EntryID;
}
set
{
Delta( ref m_EntryID, value );
}
}
public string InitialText
{
get
{
return m_InitialText;
}
set
{
Delta( ref m_InitialText, 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 GumpTextEntry(int x, int y, int width, int height, int hue, int entryID, int initialTextID)
{
m_X = x;
m_Y = y;
m_Width = width;
m_Height = height;
m_Hue = hue;
m_EntryID = entryID;
m_InitialTextID = initialTextID;
}
public override string Compile()
{
return String.Format( "{{ textentry {0} {1} {2} {3} {4} {5} {6} }}", m_X, m_Y, m_Width, m_Height, m_Hue, m_EntryID, m_InitialTextID == -1 ? Parent.Intern(m_InitialText) : m_InitialTextID);
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "textentry" );
public override void AppendTo( 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(m_InitialTextID == -1 ? Parent.Intern(m_InitialText) : m_InitialTextID);
disp.TextEntries++;
}
}
}

View File

@@ -0,0 +1,136 @@
/***************************************************************************
* GumpTextEntryLimited.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using 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;
public int X {
get {
return m_X;
}
set {
Delta( ref m_X, value );
}
}
public int Y {
get {
return m_Y;
}
set {
Delta( ref m_Y, value );
}
}
public int Width {
get {
return m_Width;
}
set {
Delta( ref m_Width, value );
}
}
public int Height {
get {
return m_Height;
}
set {
Delta( ref m_Height, value );
}
}
public int Hue {
get {
return m_Hue;
}
set {
Delta( ref m_Hue, value );
}
}
public int EntryID {
get {
return m_EntryID;
}
set {
Delta( ref m_EntryID, value );
}
}
public string InitialText {
get {
return m_InitialText;
}
set {
Delta( ref m_InitialText, value );
}
}
public int Size {
get {
return m_Size;
}
set {
Delta( ref m_Size, 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 override string Compile() {
return String.Format( "{{ textentrylimited {0} {1} {2} {3} {4} {5} {6} {7} }}", 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( 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++;
}
}
}

View File

@@ -0,0 +1,59 @@
/***************************************************************************
* GumpTooltip.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
using Server.Network;
namespace Server.Gumps
{
public class GumpTooltip : GumpEntry
{
private int m_Number;
public GumpTooltip( int number )
{
m_Number = number;
}
public int Number
{
get
{
return m_Number;
}
set
{
Delta( ref m_Number, value );
}
}
public override string Compile()
{
return string.Format("{{ tooltip {0} }}", m_Number);
}
private static byte[] m_LayoutName = Gump.StringToBuffer( "tooltip" );
public override void AppendTo( IGumpWriter disp )
{
disp.AppendLayout( m_LayoutName );
disp.AppendLayout( m_Number );
}
}
}

116
Server/Gumps/RelayInfo.cs Normal file
View File

@@ -0,0 +1,116 @@
/***************************************************************************
* RelayInfo.cs
* -------------------
* begin : May 1, 2002
* copyright : (C) The RunUO Software Team
* email : info@runuo.com
*
* $Id$
*
***************************************************************************/
/***************************************************************************
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
***************************************************************************/
using System;
namespace Server.Gumps
{
public class TextRelay
{
private int m_EntryID;
private string m_Text;
public TextRelay( int entryID, string text )
{
m_EntryID = entryID;
m_Text = text;
}
public int EntryID
{
get
{
return m_EntryID;
}
}
public string Text
{
get
{
return m_Text;
}
}
}
public class RelayInfo
{
private int m_ButtonID;
private int[] m_Switches;
private TextRelay[] m_TextEntries;
public RelayInfo( int buttonID, int[] switches, TextRelay[] textEntries )
{
m_ButtonID = buttonID;
m_Switches = switches;
m_TextEntries = textEntries;
}
public int ButtonID
{
get
{
return m_ButtonID;
}
}
public int[] Switches
{
get
{
return m_Switches;
}
}
public TextRelay[] TextEntries
{
get
{
return m_TextEntries;
}
}
public bool IsSwitched( int switchID )
{
for ( int i = 0; i < m_Switches.Length; ++i )
{
if ( m_Switches[i] == switchID )
{
return true;
}
}
return false;
}
public TextRelay GetTextEntry( int entryID )
{
for ( int i = 0; i < m_TextEntries.Length; ++i )
{
if ( m_TextEntries[i].EntryID == entryID )
{
return m_TextEntries[i];
}
}
return null;
}
}
}

38
Server/HuePicker.cs Normal file
View File

@@ -0,0 +1,38 @@
#region References
using Server.Network;
#endregion
namespace Server.HuePickers
{
public class HuePicker
{
private static int m_NextSerial = 1;
private readonly int m_Serial;
private readonly int m_ItemID;
public int Serial { get { return m_Serial; } }
public int ItemID { get { return m_ItemID; } }
public HuePicker(int itemID)
{
do
{
m_Serial = m_NextSerial++;
}
while (m_Serial == 0);
m_ItemID = itemID;
}
public virtual void OnResponse(int hue)
{ }
public void SendTo(NetState state)
{
state.Send(new DisplayHuePicker(this));
state.AddHuePicker(this);
}
}
}

285
Server/IAccount.cs Normal file
View File

@@ -0,0 +1,285 @@
#region References
using System;
#endregion
namespace Server.Accounting
{
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>
/// 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;
public static double GetGoldTotal(Mobile m)
{
if (m == null)
{
return 0;
}
return GetGoldTotal(m.Account);
}
public static double GetGoldTotal(IGoldAccount a)
{
if (a == null)
{
return 0;
}
int gold;
double totalGold;
a.GetGoldBalance(out gold, out totalGold);
return totalGold;
}
public static double GetPlatTotal(Mobile m)
{
if (m == null)
{
return 0;
}
return GetPlatTotal(m.Account);
}
public static double GetPlatTotal(IGoldAccount a)
{
if (a == null)
{
return 0;
}
int plat;
double totalPlat;
a.GetPlatBalance(out plat, out totalPlat);
return totalPlat;
}
}
public interface IGoldAccount
{
/// <summary>
/// This amount represents the total amount of currency owned by the player.
/// It is cumulative of both Gold and Platinum, the absolute total amount of
/// Gold owned by the player can be found by multiplying this value by the
/// CurrencyThreshold value.
/// </summary>
[CommandProperty(AccessLevel.Administrator)]
double TotalCurrency { get; }
/// <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>
/// Attempts to deposit the given amount of Gold and 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 DepositCurrency(double 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 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(long 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(long amount);
/// <summary>
/// Attempts to withdraw the given amount of Platinum and Gold from this account.
/// </summary>
/// <param name="amount">Amount to withdraw.</param>
/// <returns>True if successful, false if balance was too low.</returns>
bool WithdrawCurrency(double 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(long 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(long amount);
/// <summary>
/// Gets the total balance of Gold for this account.
/// </summary>
/// <param name="gold">Gold value, Platinum exclusive</param>
/// <param name="totalGold">Gold value, Platinum inclusive</param>
void GetGoldBalance(out int gold, out double totalGold);
/// <summary>
/// Gets the total balance of Gold for this account.
/// </summary>
/// <param name="gold">Gold value, Platinum exclusive</param>
/// <param name="totalGold">Gold value, Platinum inclusive</param>
void GetGoldBalance(out long gold, out double totalGold);
/// <summary>
/// Gets the total balance of Platinum for this account.
/// </summary>
/// <param name="plat">Platinum value, Gold exclusive</param>
/// <param name="totalPlat">Platinum value, Gold inclusive</param>
void GetPlatBalance(out int plat, out double totalPlat);
/// <summary>
/// Gets the total balance of Platinum for this account.
/// </summary>
/// <param name="plat">Platinum value, Gold exclusive</param>
/// <param name="totalPlat">Platinum value, Gold inclusive</param>
void GetPlatBalance(out long plat, out double totalPlat);
/// <summary>
/// Gets the total balance of Gold and Platinum for this account.
/// </summary>
/// <param name="gold">Gold value, Platinum exclusive</param>
/// <param name="totalGold">Gold value, Platinum inclusive</param>
/// <param name="plat">Platinum value, Gold exclusive</param>
/// <param name="totalPlat">Platinum value, Gold inclusive</param>
void GetBalance(out int gold, out double totalGold, out int plat, out double totalPlat);
/// <summary>
/// Gets the total balance of Gold and Platinum for this account.
/// </summary>
/// <param name="gold">Gold value, Platinum exclusive</param>
/// <param name="totalGold">Gold value, Platinum inclusive</param>
/// <param name="plat">Platinum value, Gold exclusive</param>
/// <param name="totalPlat">Platinum value, Gold inclusive</param>
void GetBalance(out long gold, out double totalGold, out long plat, out double totalPlat);
bool HasGoldBalance(double amount);
bool HasPlatBalance(double amount);
}
public interface IAccount : IGoldAccount, IComparable<IAccount>
{
[CommandProperty(AccessLevel.Administrator, true)]
string Username { get; set; }
[CommandProperty(AccessLevel.Administrator, true)]
string Email { get; set; }
[CommandProperty(AccessLevel.Administrator, AccessLevel.Owner)]
AccessLevel AccessLevel { get; set; }
[CommandProperty(AccessLevel.Administrator)]
int Length { get; }
[CommandProperty(AccessLevel.Administrator)]
int Limit { get; }
[CommandProperty(AccessLevel.Administrator)]
int Count { get; }
[CommandProperty(AccessLevel.Administrator, true)]
DateTime Created { get; set; }
[CommandProperty(AccessLevel.Administrator, true)]
DateTime LastLogin { get; set; }
[CommandProperty(AccessLevel.Administrator)]
TimeSpan Age { get; }
[CommandProperty(AccessLevel.Administrator)]
TimeSpan TotalGameTime { get; }
[CommandProperty(AccessLevel.Administrator)]
bool Banned { get; set; }
[CommandProperty(AccessLevel.Administrator)]
bool Young { get; set; }
Mobile this[int index] { get; set; }
void Delete();
void SetPassword(string password);
bool CheckPassword(string password);
}
}

105
Server/IEntity.cs Normal file
View File

@@ -0,0 +1,105 @@
#region References
using System;
#endregion
namespace Server
{
public interface IEntity : IPoint3D, IComparable, IComparable<IEntity>
{
Serial Serial { get; }
Point3D Location { get; set; }
Map Map { get; set; }
bool NoMoveHS { get; set; }
Direction Direction { get; set; }
string Name { get; set; }
int Hue { get; set; }
bool Deleted { get; }
void Delete();
void ProcessDelta();
void InvalidateProperties();
void OnStatsQuery(Mobile m);
}
public class Entity : IEntity, IComparable<Entity>
{
public Serial Serial { get; private set; }
public Point3D Location { get; set; }
public Map Map { get; set; }
public int X { get { return Location.X; } }
public int Y { get { return Location.Y; } }
public int Z { get { return Location.Z; } }
public bool Deleted { get; private set; }
public bool NoMoveHS { get; set; }
Direction IEntity.Direction { get; set; }
string IEntity.Name { get; set; }
int IEntity.Hue { get; set; }
public Entity(Serial serial, Point3D loc, Map map)
{
Serial = serial;
Location = loc;
Map = map;
}
public int CompareTo(IEntity other)
{
if (other == null)
{
return -1;
}
return Serial.CompareTo(other.Serial);
}
public int CompareTo(Entity other)
{
return CompareTo((IEntity)other);
}
public int CompareTo(object other)
{
if (other == null || other is IEntity)
{
return CompareTo((IEntity)other);
}
throw new ArgumentException();
}
public void Delete()
{
if (Deleted)
{
return;
}
Deleted = true;
Location = Point3D.Zero;
Map = null;
}
void IEntity.ProcessDelta()
{ }
void IEntity.InvalidateProperties()
{ }
void IEntity.OnStatsQuery(Mobile m)
{ }
}
}

65
Server/Insensitive.cs Normal file
View File

@@ -0,0 +1,65 @@
#region References
using System.Collections;
#endregion
namespace Server
{
public static class Insensitive
{
private static readonly IComparer m_Comparer = CaseInsensitiveComparer.Default;
public static IComparer Comparer { get { return m_Comparer; } }
public static int Compare(string a, string b)
{
return m_Comparer.Compare(a, b);
}
public static bool Equals(string a, string b)
{
if (a == null && b == null)
{
return true;
}
else if (a == null || b == null || a.Length != b.Length)
{
return false;
}
return (m_Comparer.Compare(a, b) == 0);
}
public static bool StartsWith(string a, string b)
{
if (a == null || b == null || a.Length < b.Length)
{
return false;
}
return (m_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;
}
return (m_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;
}
a = a.ToLower();
b = b.ToLower();
return (a.IndexOf(b) >= 0);
}
}
}

145
Server/Interfaces.cs Normal file
View File

@@ -0,0 +1,145 @@
#region References
using System;
using System.Collections.Generic;
using Server.ContextMenus;
using Server.Mobiles;
#endregion
namespace Server.Mobiles
{
public interface IMount
{
Mobile Rider { get; set; }
void OnRiderDamaged(Mobile from, ref int amount, bool willKill);
}
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);
DateTime LastRestock { get; set; }
TimeSpan RestockDelay { get; }
void Restock();
}
public interface IPoint2D
{
int X { get; }
int Y { get; }
}
public interface IPoint3D : IPoint2D
{
int Z { get; }
}
public interface ICarvable
{
bool Carve(Mobile from, Item item);
}
public interface IWeapon
{
int MaxRange { get; }
void OnBeforeSwing(Mobile attacker, IDamageable damageable);
TimeSpan OnSwing(Mobile attacker, IDamageable damageable);
void GetStatusDamage(Mobile from, out int min, out int max);
TimeSpan GetDelay(Mobile attacker);
}
public interface IHued
{
int HuedItemID { get; }
}
public interface ISpell
{
int ID { get; }
bool IsCasting { get; }
void OnCasterHurt();
void OnCasterKilled();
void OnConnectionChanged();
bool OnCasterMoving(Direction d);
bool CheckMovement(Mobile caster);
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 ISpawner
{
bool UnlinkOnTaming { get; }
Point3D HomeLocation { get; }
int HomeRange { get; }
void Remove(ISpawnable spawn);
void GetSpawnProperties(ISpawnable spawn, ObjectPropertyList list);
void GetSpawnContextEntries(ISpawnable spawn, Mobile m, List<ContextMenuEntry> list);
}
public interface ISpawnable : IEntity
{
void OnBeforeSpawn(Point3D location, Map map);
void MoveToWorld(Point3D location, Map map);
void OnAfterSpawn();
ISpawner Spawner { get; set; }
}
public interface IDamageable : IEntity
{
int Hits { get; set; }
int HitsMax { get; }
bool Alive { get; }
int PhysicalResistance { get; }
int FireResistance { get; }
int ColdResistance { get; }
int PoisonResistance { get; }
int EnergyResistance { get; }
int Damage(int amount, Mobile attacker);
void PlaySound(int soundID);
void MovingEffect(IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode);
void MovingEffect(IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes);
void MovingParticles(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);
void MovingParticles(IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound, int unknown);
void MovingParticles(IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown);
void MovingParticles(IEntity to, int itemID, int speed, int duration, bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound);
void FixedEffect(int itemID, int speed, int duration, int hue, int renderMode);
void FixedEffect(int itemID, int speed, int duration);
void FixedParticles(int itemID, int speed, int duration, int effect, int hue, int renderMode, EffectLayer layer, int unknown);
void FixedParticles(int itemID, int speed, int duration, int effect, int hue, int renderMode, EffectLayer layer);
void FixedParticles(int itemID, int speed, int duration, int effect, EffectLayer layer, int unknown);
void FixedParticles(int itemID, int speed, int duration, int effect, EffectLayer layer);
void BoltEffect(int hue);
}
public interface IArtifact
{
int ArtifactRarity { get; }
}
}

6496
Server/Item.cs Normal file

File diff suppressed because it is too large Load Diff

45
Server/ItemBounds.cs Normal file
View File

@@ -0,0 +1,45 @@
#region References
using System;
using System.IO;
#endregion
namespace Server
{
public static class ItemBounds
{
private static readonly Rectangle2D[] m_Bounds;
public static Rectangle2D[] Table { get { return m_Bounds; } }
static ItemBounds()
{
m_Bounds = 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);
int count = Math.Min(m_Bounds.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();
m_Bounds[i].Set(xMin, yMin, (xMax - xMin) + 1, (yMax - yMin) + 1);
}
bin.Close();
}
}
else
{
Console.WriteLine("Warning: Data/Binary/Bounds.bin does not exist");
}
}
}
}

177
Server/Items/BaseMulti.cs Normal file
View File

@@ -0,0 +1,177 @@
#region References
using Server.Network;
using System;
#endregion
namespace Server.Items
{
public class BaseMulti : Item
{
[Constructable]
public BaseMulti(int itemID)
: base(itemID)
{
Movable = false;
}
public BaseMulti(Serial serial)
: base(serial)
{ }
[CommandProperty(AccessLevel.GameMaster)]
public override int ItemID
{
get { return base.ItemID; }
set
{
if (base.ItemID != value)
{
Map facet = (Parent == null ? Map : null);
if (facet != null)
{
facet.OnLeave(this);
}
base.ItemID = value;
if (facet != null)
{
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;
if (facet != null)
{
facet.OnLeave(this);
facet.OnEnter(this);
}
}
}
public override int LabelNumber
{
get
{
MultiComponentList mcl = Components;
if (mcl.List.Length > 0)
{
int id = mcl.List[0].m_ItemID;
if (id < 0x4000)
{
return 1020000 + id;
}
else
{
return 1078872 + id;
}
}
return base.LabelNumber;
}
}
public virtual bool AllowsRelativeDrop { get { return false; } }
public override int GetUpdateRange(Mobile m)
{
int min = m.NetState != null ? m.NetState.UpdateRange : Core.GlobalUpdateRange;
int max = Core.GlobalRadarRange - 1;
int w = Components.Width;
int h = Components.Height - 1;
int v = min + ((w > h ? w : h) / 2);
if (v > max)
v = max;
else if (v < min)
v = min;
return v;
}
public virtual MultiComponentList Components { get { return MultiData.GetComponents(ItemID); } }
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(IPoint3D p)
{
return Contains(p.X, p.Y);
}
public virtual bool Contains(int x, int y)
{
MultiComponentList mcl = Components;
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;
}
public bool Contains(Mobile m)
{
if (m.Map == Map)
{
return Contains(m.X, m.Y);
}
else
{
return false;
}
}
public bool Contains(Item item)
{
if (item.Map == Map)
{
return Contains(item.X, item.Y);
}
else
{
return false;
}
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(1); // version
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
int version = reader.ReadInt();
if (version == 0)
{
if (ItemID >= 0x4000)
{
ItemID -= 0x4000;
}
}
}
}
}

2198
Server/Items/Container.cs Normal file

File diff suppressed because it is too large Load Diff

163
Server/Items/Containers.cs Normal file
View File

@@ -0,0 +1,163 @@
#region References
using System;
using Server.Accounting;
using Server.Network;
#endregion
namespace Server.Items
{
public class BankBox : Container
{
private static readonly Type _GoldType = ScriptCompiler.FindTypeByFullName("Server.Items.Gold");
private static readonly Type _CheckType = ScriptCompiler.FindTypeByFullName("Server.Items.BankCheck");
public static bool SendDeleteOnClose { get; set; }
private Mobile m_Owner;
private bool m_Open;
public override int DefaultMaxWeight { get { return 0; } }
public override bool IsVirtualItem { get { return true; } }
public Mobile Owner { get { return m_Owner; } }
public bool Opened { get { return m_Open; } }
public BankBox(Mobile owner)
: base(0xE7C)
{
m_Owner = owner;
Movable = false;
Layer = Layer.Bank;
}
public BankBox(Serial serial)
: base(serial)
{ }
public void Open()
{
if (m_Owner != null && m_Owner.NetState != null)
{
m_Open = true;
m_Owner.PrivateOverheadMessage(
MessageType.Regular,
0x3B2,
true,
String.Format("Bank container has {0} items, {1} stones", TotalItems, TotalWeight),
m_Owner.NetState);
m_Owner.Send(new EquipUpdate(this));
DisplayTo(m_Owner);
}
}
public void Close()
{
m_Open = false;
if (m_Owner != null && SendDeleteOnClose)
{
m_Owner.Send(RemovePacket);
}
}
public override void OnSingleClick(Mobile from)
{ }
public override void OnDoubleClick(Mobile from)
{ }
public override DeathMoveResult OnParentDeath(Mobile parent)
{
return DeathMoveResult.RemainEquiped;
}
public override bool IsAccessibleTo(Mobile check)
{
if ((check == m_Owner && m_Open) || check.AccessLevel >= AccessLevel.GameMaster)
{
return base.IsAccessibleTo(check);
}
return false;
}
public override bool OnDragDrop(Mobile from, Item dropped)
{
if ((from == m_Owner && m_Open) || from.AccessLevel >= AccessLevel.GameMaster)
{
return base.OnDragDrop(from, dropped);
}
return false;
}
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
{
if ((from == m_Owner && m_Open) || from.AccessLevel >= AccessLevel.GameMaster)
{
return base.OnDragDropInto(from, item, p);
}
return false;
}
public override int GetTotal(TotalType type)
{
if (AccountGold.Enabled && Owner != null && Owner.Account != null && type == TotalType.Gold)
{
return Owner.Account.TotalGold;
}
return base.GetTotal(type);
}
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
{
Type type = item.GetType();
if (AccountGold.Enabled && Owner != null && Owner.Account != null && (type.IsAssignableFrom(_GoldType) || type.IsAssignableFrom(_CheckType)))
{
return true;
}
return base.CheckHold(m, item, message, checkItems, plusItems, plusWeight);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0); // version
writer.Write(m_Owner);
writer.Write(m_Open);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt();
m_Owner = reader.ReadMobile();
m_Open = reader.ReadBool();
if (ItemID == 0xE41)
{
ItemID = 0xE7C;
}
if (m_Owner == null)
{
Delete();
}
}
}
}

View File

@@ -0,0 +1,129 @@
#region References
using Server.Accounting;
using Server.Network;
#endregion
namespace Server.Items
{
public class SecureTradeContainer : Container
{
private readonly SecureTrade m_Trade;
public SecureTrade Trade { get { return m_Trade; } }
public SecureTradeContainer(SecureTrade trade)
: base(0x1E5E)
{
m_Trade = trade;
Movable = false;
Layer = Layer.SecureTrade;
}
public SecureTradeContainer(Serial serial)
: base(serial)
{ }
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;
}
var to = Trade.From.Container != this ? Trade.From.Mobile : Trade.To.Mobile;
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 IsAccessibleTo(Mobile check)
{
if (!IsChildOf(check) || m_Trade == null || !m_Trade.Valid)
{
return false;
}
return base.IsAccessibleTo(check);
}
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 OnSubItemAdded(Item item)
{
if (!(item is VirtualCheck))
{
ClearChecks();
}
}
public override void OnSubItemRemoved(Item item)
{
if (!(item is VirtualCheck))
{
ClearChecks();
}
}
public void ClearChecks()
{
if (m_Trade != null)
{
if (m_Trade.From != null && !m_Trade.From.IsDisposed)
{
m_Trade.From.Accepted = false;
}
if (m_Trade.To != null && !m_Trade.To.IsDisposed)
{
m_Trade.To.Accepted = false;
}
m_Trade.Update();
}
}
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);
}
public override void Serialize(GenericWriter writer)
{
base.Serialize(writer);
writer.Write(0);
}
public override void Deserialize(GenericReader reader)
{
base.Deserialize(reader);
reader.ReadInt();
}
}
}

View File

@@ -0,0 +1,389 @@
#region References
using System;
using System.Drawing;
using Server.Accounting;
using Server.Gumps;
using Server.Network;
#endregion
namespace Server
{
public sealed class VirtualCheck : Item
{
public static bool UseEditGump = false;
public override bool IsVirtualItem { get { return true; } }
public override bool DisplayWeight { get { return false; } }
public override bool DisplayLootType { get { return false; } }
public override double DefaultWeight { get { return 0; } }
public override string DefaultName { get { return "Offer Of Currency"; } }
public EditGump Editor { get; private set; }
private int _Plat;
[CommandProperty(AccessLevel.Administrator)]
public int Plat
{
get { return _Plat; }
set
{
_Plat = value;
InvalidateProperties();
}
}
private int _Gold;
[CommandProperty(AccessLevel.Administrator)]
public int Gold
{
get { return _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 == null || 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, String.Format("{0:#,0} platinum, {1:#,0} gold", Plat, Gold)); // value: ~1_val~
}
public void UpdateTrade(Mobile user)
{
var c = GetSecureTradeCont();
if (c == null || 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 = String.Format(
"<BASEFONT COLOR=#{0:X6}><CENTER>BANK OF {1}</CENTER>",
Color.DarkSlateGray.ToArgb() & 0x00FFFFFF,
User.RawName.ToUpper());
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 (!Int32.TryParse(platText, out _Plat))
{
User.SendMessage("That is not a valid amount of platinum.");
refresh = true;
}
else if (!Int32.TryParse(goldText, out _Gold))
{
User.SendMessage("That is not a valid amount of gold.");
refresh = true;
}
else
{
var cur = User.Account.TotalCurrency;
var off = _Plat + (_Gold / Math.Max(1.0, AccountGold.CurrencyThreshold));
if (off > cur)
{
_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();
}
}
}
}

209
Server/Items/VirtualHair.cs Normal file
View File

@@ -0,0 +1,209 @@
#region References
using Server.Network;
#endregion
namespace Server
{
public abstract class BaseHairInfo
{
private int m_ItemID;
private int m_Hue;
[CommandProperty(AccessLevel.GameMaster)]
public int ItemID { get { return m_ItemID; } set { m_ItemID = value; } }
[CommandProperty(AccessLevel.GameMaster)]
public int Hue { get { return m_Hue; } set { m_Hue = value; } }
protected BaseHairInfo(int itemid)
: this(itemid, 0)
{ }
protected BaseHairInfo(int itemid, int hue)
{
m_ItemID = itemid;
m_Hue = hue;
}
protected BaseHairInfo(GenericReader reader)
{
int version = reader.ReadInt();
switch (version)
{
case 0:
{
m_ItemID = reader.ReadInt();
m_Hue = reader.ReadInt();
break;
}
}
}
public virtual void Serialize(GenericWriter writer)
{
writer.Write(0); //version
writer.Write(m_ItemID);
writer.Write(m_Hue);
}
}
public class HairInfo : BaseHairInfo
{
public HairInfo(int itemid)
: base(itemid, 0)
{ }
public HairInfo(int itemid, int hue)
: base(itemid, hue)
{ }
public HairInfo(GenericReader reader)
: base(reader)
{ }
public static int FakeSerial(Mobile parent)
{
return (0x7FFFFFFF - 0x400 - (parent.Serial * 4));
}
}
public class FacialHairInfo : BaseHairInfo
{
public FacialHairInfo(int itemid)
: base(itemid, 0)
{ }
public FacialHairInfo(int itemid, int hue)
: base(itemid, hue)
{ }
public FacialHairInfo(GenericReader reader)
: base(reader)
{ }
public static int FakeSerial(Mobile parent)
{
return (0x7FFFFFFF - 0x400 - 1 - (parent.Serial * 4));
}
}
public class FaceInfo : BaseHairInfo
{
public FaceInfo(int itemid)
: base(itemid, 0)
{
}
public FaceInfo(int itemid, int hue)
: base(itemid, hue)
{
}
public FaceInfo(GenericReader reader)
: base(reader)
{
}
public static int FakeSerial(Mobile parent)
{
return (0x7FFFFFFF - 0x400 - 2 - (parent.Serial * 4));
}
}
public sealed class HairEquipUpdate : Packet
{
public HairEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
int hue = parent.HairHue;
if (parent.SolidHueOverride >= 0)
{
hue = parent.SolidHueOverride;
}
int hairSerial = HairInfo.FakeSerial(parent);
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;
if (parent.SolidHueOverride >= 0)
{
hue = parent.SolidHueOverride;
}
int hairSerial = FacialHairInfo.FakeSerial(parent);
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 FaceEquipUpdate : Packet
{
public FaceEquipUpdate(Mobile parent)
: base(0x2E, 15)
{
int hue = parent.FaceHue;
if (parent.SolidHueOverride >= 0)
{
hue = parent.SolidHueOverride;
}
int faceSerial = FaceInfo.FakeSerial(parent);
m_Stream.Write((int)faceSerial);
m_Stream.Write((short)parent.FaceItemID);
m_Stream.Write((byte)0);
m_Stream.Write((byte)Layer.Face);
m_Stream.Write((int)parent.Serial);
m_Stream.Write((short)hue);
}
}
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(FacialHairInfo.FakeSerial(parent));
}
}
public sealed class RemoveFace : Packet
{
public RemoveFace(Mobile parent)
: base(0x1D, 5)
{
m_Stream.Write((int)FaceInfo.FakeSerial(parent));
}
}
}

65
Server/KeywordList.cs Normal file
View File

@@ -0,0 +1,65 @@
namespace Server
{
public class KeywordList
{
private int[] m_Keywords;
private int m_Count;
public KeywordList()
{
m_Keywords = new int[8];
m_Count = 0;
}
public int Count { get { return m_Count; } }
public bool Contains(int keyword)
{
bool contains = false;
for (int i = 0; !contains && i < m_Count; ++i)
{
contains = (keyword == m_Keywords[i]);
}
return contains;
}
public void Add(int keyword)
{
if ((m_Count + 1) > m_Keywords.Length)
{
var old = m_Keywords;
m_Keywords = new int[old.Length * 2];
for (int i = 0; i < old.Length; ++i)
{
m_Keywords[i] = old[i];
}
}
m_Keywords[m_Count++] = keyword;
}
private static readonly int[] m_EmptyInts = new int[0];
public int[] ToArray()
{
if (m_Count == 0)
{
return m_EmptyInts;
}
var keywords = new int[m_Count];
for (int i = 0; i < m_Count; ++i)
{
keywords[i] = m_Keywords[i];
}
m_Count = 0;
return keywords;
}
}
}

1029
Server/Main.cs Normal file

File diff suppressed because it is too large Load Diff

3188
Server/Map.cs Normal file

File diff suppressed because it is too large Load Diff

15
Server/Menus/IMenu.cs Normal file
View File

@@ -0,0 +1,15 @@
#region References
using Server.Network;
#endregion
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);
}
}

View File

@@ -0,0 +1,74 @@
#region References
using Server.Network;
#endregion
namespace Server.Menus.ItemLists
{
public class ItemListEntry
{
private readonly string m_Name;
private readonly int m_ItemID;
private readonly int m_Hue;
public string Name { get { return m_Name; } }
public int ItemID { get { return m_ItemID; } }
public int Hue { get { return m_Hue; } }
public ItemListEntry(string name, int itemID)
: this(name, itemID, 0)
{ }
public ItemListEntry(string name, int itemID, int hue)
{
m_Name = name;
m_ItemID = itemID;
m_Hue = hue;
}
}
public class ItemListMenu : IMenu
{
private readonly string m_Question;
private ItemListEntry[] m_Entries;
private readonly int m_Serial;
private static int m_NextSerial;
int IMenu.Serial { get { return m_Serial; } }
int IMenu.EntryLength { get { return m_Entries.Length; } }
public string Question { get { return m_Question; } }
public ItemListEntry[] Entries { get { return m_Entries; } set { m_Entries = value; } }
public ItemListMenu(string question, ItemListEntry[] entries)
{
m_Question = question;
m_Entries = entries;
do
{
m_Serial = m_NextSerial++;
m_Serial &= 0x7FFFFFFF;
}
while (m_Serial == 0);
m_Serial = (int)((uint)m_Serial | 0x80000000);
}
public virtual void OnCancel(NetState state)
{ }
public virtual void OnResponse(NetState state, int index)
{ }
public void SendTo(NetState state)
{
state.AddMenu(this);
state.Send(new DisplayItemListMenu(this));
}
}
}

View File

@@ -0,0 +1,47 @@
#region References
using Server.Network;
#endregion
namespace Server.Menus.Questions
{
public class QuestionMenu : IMenu
{
private readonly string[] m_Answers;
private readonly int m_Serial;
private static int m_NextSerial;
int IMenu.Serial { get { return m_Serial; } }
int IMenu.EntryLength { get { return m_Answers.Length; } }
public string Question { get; set; }
public string[] Answers { get { return m_Answers; } }
public QuestionMenu(string question, string[] answers)
{
Question = question;
m_Answers = answers;
do
{
m_Serial = ++m_NextSerial;
m_Serial &= 0x7FFFFFFF;
}
while (m_Serial == 0);
}
public virtual void OnCancel(NetState state)
{ }
public virtual void OnResponse(NetState state, int index)
{ }
public void SendTo(NetState state)
{
state.AddMenu(this);
state.Send(new DisplayQuestionMenu(this));
}
}
}

12837
Server/Mobile.cs Normal file

File diff suppressed because it is too large Load Diff

72
Server/Movement.cs Normal file
View File

@@ -0,0 +1,72 @@
namespace Server.Movement
{
public static class Movement
{
private static IMovementImpl m_Impl;
public static IMovementImpl Impl { get { return m_Impl; } set { m_Impl = value; } }
/*public static bool CheckMovement(IPoint3D p, Direction d, out int newZ)
{
if (m_Impl != null)
{
return m_Impl.CheckMovement(p, d, out newZ);
}
newZ = p.Z;
return false;
}*/
public static bool CheckMovement(IPoint3D p, Map map, Point3D loc, Direction d, out int newZ)
{
if (m_Impl != null)
{
return m_Impl.CheckMovement(p, map, loc, d, out newZ);
}
newZ = p.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 interface IMovementImpl
{
//bool CheckMovement(IPoint3D p, Direction d, out int newZ);
bool CheckMovement(IPoint3D p, Map map, Point3D loc, Direction d, out int newZ);
}
}

996
Server/MultiData.cs Normal file
View File

@@ -0,0 +1,996 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Server;
using Server.Network;
#endregion
namespace Server
{
public static class MultiData
{
public static Dictionary<int, MultiComponentList> Components { get { return m_Components; } }
private static readonly Dictionary<int, MultiComponentList> m_Components;
private static readonly BinaryReader m_IndexReader;
private static readonly BinaryReader m_StreamReader;
public static bool UsingUOPFormat { get; private set; }
public static MultiComponentList GetComponents(int multiID)
{
MultiComponentList mcl;
multiID &= 0x3FFF; // The value of the actual multi is shifted by 0x4000, so this is left alone.
if (m_Components.ContainsKey(multiID))
{
mcl = m_Components[multiID];
}
else if (!UsingUOPFormat)
{
m_Components[multiID] = mcl = Load(multiID);
}
else
{
mcl = MultiComponentList.Empty;
}
return mcl;
}
public static MultiComponentList Load(int multiID)
{
try
{
m_IndexReader.BaseStream.Seek(multiID * 12, SeekOrigin.Begin);
int lookup = m_IndexReader.ReadInt32();
int length = m_IndexReader.ReadInt32();
if (lookup < 0 || length <= 0)
{
return MultiComponentList.Empty;
}
m_StreamReader.BaseStream.Seek(lookup, SeekOrigin.Begin);
return new MultiComponentList(m_StreamReader, length / (MultiComponentList.PostHSFormat ? 16 : 12));
}
catch
{
return MultiComponentList.Empty;
}
}
public static void UOPLoad(string path)
{
var stream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read);
BinaryReader streamReader = new BinaryReader(stream);
// Head Information Start
if (streamReader.ReadInt32() != 0x0050594D) // Not a UOP Files
return;
if (streamReader.ReadInt32() > 5) // Bad Version
return;
// Multi ID List Array Start
var chunkIds = new Dictionary<ulong, int>();
var chunkIds2 = new Dictionary<ulong, int>();
UOPHash.BuildChunkIDs(ref chunkIds, ref chunkIds2);
// Multi ID List Array End
streamReader.ReadUInt32(); // format timestamp? 0xFD23EC43
long startAddress = streamReader.ReadInt64();
int blockSize = streamReader.ReadInt32(); // files in each block
int totalSize = streamReader.ReadInt32(); // Total File Count
stream.Seek(startAddress, SeekOrigin.Begin); // Head Information End
long nextBlock;
do
{
int blockFileCount = streamReader.ReadInt32();
nextBlock = streamReader.ReadInt64();
int index = 0;
do
{
long offset = streamReader.ReadInt64();
int headerSize = streamReader.ReadInt32(); // header length
int compressedSize = streamReader.ReadInt32(); // compressed size
int decompressedSize = streamReader.ReadInt32(); // decompressed size
ulong filehash = streamReader.ReadUInt64(); // filename hash (HashLittle2)
uint datablockhash = streamReader.ReadUInt32(); // data hash (Adler32)
short flag = streamReader.ReadInt16(); // compression method (0 = none, 1 = zlib)
index++;
if (offset == 0 || decompressedSize == 0 || filehash == 0x126D1E99DDEDEE0A) // Exclude housing.bin
continue;
// Multi ID Search Start
int chunkID = -1;
if (!chunkIds.TryGetValue(filehash, out chunkID))
{
int tmpChunkID = 0;
if (chunkIds2.TryGetValue(filehash, out tmpChunkID))
{
chunkID = tmpChunkID;
}
}
// Multi ID Search End
long positionpoint = stream.Position; // save current position
// Decompress Data Start
stream.Seek(offset + headerSize, SeekOrigin.Begin);
byte[] sourceData = new byte[compressedSize];
if (stream.Read(sourceData, 0, compressedSize) != compressedSize)
continue;
byte[] data;
if (flag == 1)
{
byte[] destData = new byte[decompressedSize];
/*ZLibError error = */Compression.Compressor.Decompress(destData, ref decompressedSize, sourceData, compressedSize);
data = destData;
}
else
{
data = sourceData;
}
// End Decompress Data
var tileList = new List<MultiTileEntry>();
using (MemoryStream fs = new MemoryStream(data))
{
using (BinaryReader reader = new BinaryReader(fs))
{
uint a = reader.ReadUInt32();
uint count = reader.ReadUInt32();
for (uint i = 0; i < count; i++)
{
ushort ItemId = reader.ReadUInt16();
short x = reader.ReadInt16();
short y = reader.ReadInt16();
short z = reader.ReadInt16();
ushort flagint = reader.ReadUInt16();
TileFlag flagg;
switch (flagint)
{
default:
case 0: { flagg = TileFlag.Background; break; }
case 1: { flagg = TileFlag.None; break; }
case 257: { flagg = TileFlag.Generic; break; }
}
uint clilocsCount = reader.ReadUInt32();
if (clilocsCount != 0)
{
fs.Seek(fs.Position + (clilocsCount * 4), SeekOrigin.Begin); // binary block bypass
}
tileList.Add(new MultiTileEntry(ItemId, x, y, z, flagg));
}
reader.Close();
}
}
m_Components[chunkID] = new MultiComponentList(tileList);
stream.Seek(positionpoint, SeekOrigin.Begin); // back to position
}
while (index < blockFileCount);
}
while (stream.Seek(nextBlock, SeekOrigin.Begin) != 0);
chunkIds.Clear();
chunkIds2.Clear();
}
static MultiData()
{
m_Components = new Dictionary<int, MultiComponentList>();
string multicollectionPath = Core.FindDataFile("MultiCollection.uop");
if (File.Exists(multicollectionPath))
{
UOPLoad(multicollectionPath);
UsingUOPFormat = true;
}
else
{
string idxPath = Core.FindDataFile("multi.idx");
string mulPath = Core.FindDataFile("multi.mul");
if (File.Exists(idxPath) && File.Exists(mulPath))
{
var idx = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_IndexReader = new BinaryReader(idx);
var stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read);
m_StreamReader = new BinaryReader(stream);
string vdPath = Core.FindDataFile("verdata.mul");
if (File.Exists(vdPath))
{
using (FileStream fs = new FileStream(vdPath, FileMode.Open, FileAccess.Read, FileShare.Read))
{
BinaryReader bin = new BinaryReader(fs);
int count = bin.ReadInt32();
for (int i = 0; i < count; ++i)
{
int file = bin.ReadInt32();
int index = bin.ReadInt32();
int lookup = bin.ReadInt32();
int length = bin.ReadInt32();
/*int extra = */
bin.ReadInt32();
if (file == 14 && index >= 0 && lookup >= 0 && length > 0)
{
bin.BaseStream.Seek(lookup, SeekOrigin.Begin);
m_Components[index] = new MultiComponentList(bin, length / 12);
bin.BaseStream.Seek(24 + (i * 20), SeekOrigin.Begin);
}
}
bin.Close();
}
}
else
{
Console.WriteLine("Warning: Multi data files not found!");
}
}
}
}
}
public struct MultiTileEntry
{
public ushort m_ItemID;
public short m_OffsetX, m_OffsetY, m_OffsetZ;
public TileFlag m_Flags;
public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, TileFlag flags)
{
m_ItemID = itemID;
m_OffsetX = xOffset;
m_OffsetY = yOffset;
m_OffsetZ = zOffset;
m_Flags = flags;
}
}
public sealed class MultiComponentList
{
public static bool PostHSFormat { get; set; }
private Point2D m_Min, m_Max, m_Center;
private int m_Width, m_Height;
private StaticTile[][][] m_Tiles;
private MultiTileEntry[] m_List;
public static readonly MultiComponentList Empty = new MultiComponentList();
public Point2D Min { get { return m_Min; } }
public Point2D Max { get { return m_Max; } }
public Point2D Center { get { return m_Center; } }
public int Width { get { return m_Width; } }
public int Height { get { return m_Height; } }
public StaticTile[][][] Tiles { get { return m_Tiles; } }
public MultiTileEntry[] List { get { return m_List; } }
public void Add(int itemID, int x, int y, int z)
{
itemID &= TileData.MaxItemValue;
itemID |= 0x10000;
int vx = x + m_Center.m_X;
int vy = y + m_Center.m_Y;
if (vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height)
{
var oldTiles = m_Tiles[vx][vy];
for (int i = oldTiles.Length - 1; i >= 0; --i)
{
ItemData data = TileData.ItemTable[itemID & TileData.MaxItemValue];
if (oldTiles[i].Z == z && (oldTiles[i].Height > 0 == data.Height > 0))
{
bool newIsRoof = (data.Flags & TileFlag.Roof) != 0;
bool oldIsRoof = (TileData.ItemTable[oldTiles[i].ID & TileData.MaxItemValue].Flags & TileFlag.Roof) != 0;
if (newIsRoof == oldIsRoof)
{
Remove(oldTiles[i].ID, x, y, z);
}
}
}
oldTiles = m_Tiles[vx][vy];
var newTiles = new StaticTile[oldTiles.Length + 1];
for (int i = 0; i < oldTiles.Length; ++i)
{
newTiles[i] = oldTiles[i];
}
newTiles[oldTiles.Length] = new StaticTile((ushort)itemID, (sbyte)z);
m_Tiles[vx][vy] = newTiles;
var oldList = m_List;
var newList = new MultiTileEntry[oldList.Length + 1];
for (int i = 0; i < oldList.Length; ++i)
{
newList[i] = oldList[i];
}
newList[oldList.Length] = new MultiTileEntry((ushort)itemID, (short)x, (short)y, (short)z, TileFlag.Background);
m_List = newList;
if (x < m_Min.m_X)
{
m_Min.m_X = x;
}
if (y < m_Min.m_Y)
{
m_Min.m_Y = y;
}
if (x > m_Max.m_X)
{
m_Max.m_X = x;
}
if (y > m_Max.m_Y)
{
m_Max.m_Y = y;
}
}
}
public void RemoveXYZH(int x, int y, int z, int minHeight)
{
int vx = x + m_Center.m_X;
int vy = y + m_Center.m_Y;
if (vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height)
{
var oldTiles = m_Tiles[vx][vy];
for (int i = 0; i < oldTiles.Length; ++i)
{
StaticTile tile = oldTiles[i];
if (tile.Z == z && tile.Height >= minHeight)
{
var newTiles = new StaticTile[oldTiles.Length - 1];
for (int j = 0; j < i; ++j)
{
newTiles[j] = oldTiles[j];
}
for (int j = i + 1; j < oldTiles.Length; ++j)
{
newTiles[j - 1] = oldTiles[j];
}
m_Tiles[vx][vy] = newTiles;
break;
}
}
var oldList = m_List;
for (int i = 0; i < oldList.Length; ++i)
{
MultiTileEntry tile = oldList[i];
if (tile.m_OffsetX == (short)x && tile.m_OffsetY == (short)y && tile.m_OffsetZ == (short)z &&
TileData.ItemTable[tile.m_ItemID & TileData.MaxItemValue].Height >= minHeight)
{
var newList = new MultiTileEntry[oldList.Length - 1];
for (int j = 0; j < i; ++j)
{
newList[j] = oldList[j];
}
for (int j = i + 1; j < oldList.Length; ++j)
{
newList[j - 1] = oldList[j];
}
m_List = newList;
break;
}
}
}
}
public void Remove(int itemID, int x, int y, int z)
{
int vx = x + m_Center.m_X;
int vy = y + m_Center.m_Y;
if (vx >= 0 && vx < m_Width && vy >= 0 && vy < m_Height)
{
var oldTiles = m_Tiles[vx][vy];
for (int i = 0; i < oldTiles.Length; ++i)
{
StaticTile tile = oldTiles[i];
if (tile.ID == itemID && tile.Z == z)
{
var newTiles = new StaticTile[oldTiles.Length - 1];
for (int j = 0; j < i; ++j)
{
newTiles[j] = oldTiles[j];
}
for (int j = i + 1; j < oldTiles.Length; ++j)
{
newTiles[j - 1] = oldTiles[j];
}
m_Tiles[vx][vy] = newTiles;
break;
}
}
var oldList = m_List;
for (int i = 0; i < oldList.Length; ++i)
{
MultiTileEntry tile = oldList[i];
if (tile.m_ItemID == itemID && tile.m_OffsetX == (short)x && tile.m_OffsetY == (short)y &&
tile.m_OffsetZ == (short)z)
{
var newList = new MultiTileEntry[oldList.Length - 1];
for (int j = 0; j < i; ++j)
{
newList[j] = oldList[j];
}
for (int j = i + 1; j < oldList.Length; ++j)
{
newList[j - 1] = oldList[j];
}
m_List = newList;
break;
}
}
}
}
public void Resize(int newWidth, int newHeight)
{
int oldWidth = m_Width, oldHeight = m_Height;
var oldTiles = m_Tiles;
int totalLength = 0;
var newTiles = new StaticTile[newWidth][][];
for (int x = 0; x < newWidth; ++x)
{
newTiles[x] = new StaticTile[newHeight][];
for (int y = 0; y < newHeight; ++y)
{
if (x < oldWidth && y < oldHeight)
{
newTiles[x][y] = oldTiles[x][y];
}
else
{
newTiles[x][y] = new StaticTile[0];
}
totalLength += newTiles[x][y].Length;
}
}
m_Tiles = newTiles;
m_List = new MultiTileEntry[totalLength];
m_Width = newWidth;
m_Height = newHeight;
m_Min = Point2D.Zero;
m_Max = Point2D.Zero;
int index = 0;
for (int x = 0; x < newWidth; ++x)
{
for (int y = 0; y < newHeight; ++y)
{
var tiles = newTiles[x][y];
foreach (StaticTile tile in tiles)
{
int vx = x - m_Center.X;
int vy = y - m_Center.Y;
if (vx < m_Min.m_X)
{
m_Min.m_X = vx;
}
if (vy < m_Min.m_Y)
{
m_Min.m_Y = vy;
}
if (vx > m_Max.m_X)
{
m_Max.m_X = vx;
}
if (vy > m_Max.m_Y)
{
m_Max.m_Y = vy;
}
m_List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, TileFlag.Background);
}
}
}
}
public MultiComponentList(MultiComponentList toCopy)
{
m_Min = toCopy.m_Min;
m_Max = toCopy.m_Max;
m_Center = toCopy.m_Center;
m_Width = toCopy.m_Width;
m_Height = toCopy.m_Height;
m_Tiles = new StaticTile[m_Width][][];
for (int x = 0; x < m_Width; ++x)
{
m_Tiles[x] = new StaticTile[m_Height][];
for (int y = 0; y < m_Height; ++y)
{
m_Tiles[x][y] = new StaticTile[toCopy.m_Tiles[x][y].Length];
for (int i = 0; i < m_Tiles[x][y].Length; ++i)
{
m_Tiles[x][y][i] = toCopy.m_Tiles[x][y][i];
}
}
}
m_List = new MultiTileEntry[toCopy.m_List.Length];
for (int i = 0; i < m_List.Length; ++i)
{
m_List[i] = toCopy.m_List[i];
}
}
public void Serialize(GenericWriter writer)
{
writer.Write(2); // version;
writer.Write(m_Min);
writer.Write(m_Max);
writer.Write(m_Center);
writer.Write(m_Width);
writer.Write(m_Height);
writer.Write(m_List.Length);
foreach (MultiTileEntry ent in m_List)
{
writer.Write(ent.m_ItemID);
writer.Write(ent.m_OffsetX);
writer.Write(ent.m_OffsetY);
writer.Write(ent.m_OffsetZ);
writer.Write((ulong)ent.m_Flags);
}
}
public MultiComponentList(GenericReader reader)
{
int version = reader.ReadInt();
m_Min = reader.ReadPoint2D();
m_Max = reader.ReadPoint2D();
m_Center = reader.ReadPoint2D();
m_Width = reader.ReadInt();
m_Height = reader.ReadInt();
int length = reader.ReadInt();
var allTiles = m_List = new MultiTileEntry[length];
if (version == 0)
{
for (int i = 0; i < length; ++i)
{
int id = reader.ReadShort();
if (id >= 0x4000)
{
id -= 0x4000;
}
allTiles[i].m_ItemID = (ushort)id;
allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort();
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt();
}
}
else
{
for (int i = 0; i < length; ++i)
{
allTiles[i].m_ItemID = reader.ReadUShort();
allTiles[i].m_OffsetX = reader.ReadShort();
allTiles[i].m_OffsetY = reader.ReadShort();
allTiles[i].m_OffsetZ = reader.ReadShort();
if (version > 1)
allTiles[i].m_Flags = (TileFlag)reader.ReadULong();
else
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt();
}
}
var tiles = new TileList[m_Width][];
m_Tiles = new StaticTile[m_Width][][];
for (int x = 0; x < m_Width; ++x)
{
tiles[x] = new TileList[m_Height];
m_Tiles[x] = new StaticTile[m_Height][];
for (int y = 0; y < m_Height; ++y)
{
tiles[x][y] = new TileList();
}
}
for (int i = 0; i < allTiles.Length; ++i)
{
if (i == 0 || allTiles[i].m_Flags != 0)
{
int xOffset = allTiles[i].m_OffsetX + m_Center.m_X;
int yOffset = allTiles[i].m_OffsetY + m_Center.m_Y;
int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000);
tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ);
}
}
for (int x = 0; x < m_Width; ++x)
{
for (int y = 0; y < m_Height; ++y)
{
m_Tiles[x][y] = tiles[x][y].ToArray();
}
}
}
public MultiComponentList(BinaryReader reader, int count)
{
var allTiles = m_List = new MultiTileEntry[count];
for (int i = 0; i < count; ++i)
{
allTiles[i].m_ItemID = reader.ReadUInt16();
allTiles[i].m_OffsetX = reader.ReadInt16();
allTiles[i].m_OffsetY = reader.ReadInt16();
allTiles[i].m_OffsetZ = reader.ReadInt16();
if (PostHSFormat)
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt64();
else
allTiles[i].m_Flags = (TileFlag)reader.ReadUInt32();
MultiTileEntry e = allTiles[i];
if (i == 0 || e.m_Flags != 0)
{
if (e.m_OffsetX < m_Min.m_X)
{
m_Min.m_X = e.m_OffsetX;
}
if (e.m_OffsetY < m_Min.m_Y)
{
m_Min.m_Y = e.m_OffsetY;
}
if (e.m_OffsetX > m_Max.m_X)
{
m_Max.m_X = e.m_OffsetX;
}
if (e.m_OffsetY > m_Max.m_Y)
{
m_Max.m_Y = e.m_OffsetY;
}
}
}
m_Center = new Point2D(-m_Min.m_X, -m_Min.m_Y);
m_Width = (m_Max.m_X - m_Min.m_X) + 1;
m_Height = (m_Max.m_Y - m_Min.m_Y) + 1;
var tiles = new TileList[m_Width][];
m_Tiles = new StaticTile[m_Width][][];
for (int x = 0; x < m_Width; ++x)
{
tiles[x] = new TileList[m_Height];
m_Tiles[x] = new StaticTile[m_Height][];
for (int y = 0; y < m_Height; ++y)
{
tiles[x][y] = new TileList();
}
}
for (int i = 0; i < allTiles.Length; ++i)
{
if (i == 0 || allTiles[i].m_Flags != 0)
{
int xOffset = allTiles[i].m_OffsetX + m_Center.m_X;
int yOffset = allTiles[i].m_OffsetY + m_Center.m_Y;
int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000);
tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ);
}
}
for (int x = 0; x < m_Width; ++x)
{
for (int y = 0; y < m_Height; ++y)
{
m_Tiles[x][y] = tiles[x][y].ToArray();
}
}
}
public MultiComponentList(List<MultiTileEntry> list)
{
var allTiles = m_List = new MultiTileEntry[list.Count];
for (int i = 0; i < list.Count; ++i)
{
allTiles[i].m_ItemID = list[i].m_ItemID;
allTiles[i].m_OffsetX = list[i].m_OffsetX;
allTiles[i].m_OffsetY = list[i].m_OffsetY;
allTiles[i].m_OffsetZ = list[i].m_OffsetZ;
allTiles[i].m_Flags = list[i].m_Flags;
MultiTileEntry e = allTiles[i];
if (i == 0 || e.m_Flags != 0)
{
if (e.m_OffsetX < m_Min.m_X)
{
m_Min.m_X = e.m_OffsetX;
}
if (e.m_OffsetY < m_Min.m_Y)
{
m_Min.m_Y = e.m_OffsetY;
}
if (e.m_OffsetX > m_Max.m_X)
{
m_Max.m_X = e.m_OffsetX;
}
if (e.m_OffsetY > m_Max.m_Y)
{
m_Max.m_Y = e.m_OffsetY;
}
}
}
m_Center = new Point2D(-m_Min.m_X, -m_Min.m_Y);
m_Width = (m_Max.m_X - m_Min.m_X) + 1;
m_Height = (m_Max.m_Y - m_Min.m_Y) + 1;
var tiles = new TileList[m_Width][];
m_Tiles = new StaticTile[m_Width][][];
for (int x = 0; x < m_Width; ++x)
{
tiles[x] = new TileList[m_Height];
m_Tiles[x] = new StaticTile[m_Height][];
for (int y = 0; y < m_Height; ++y)
{
tiles[x][y] = new TileList();
}
}
for (int i = 0; i < allTiles.Length; ++i)
{
if (i == 0 || allTiles[i].m_Flags != 0)
{
int xOffset = allTiles[i].m_OffsetX + m_Center.m_X;
int yOffset = allTiles[i].m_OffsetY + m_Center.m_Y;
int itemID = ((allTiles[i].m_ItemID & TileData.MaxItemValue) | 0x10000);
tiles[xOffset][yOffset].Add((ushort)itemID, (sbyte)allTiles[i].m_OffsetZ);
}
}
for (int x = 0; x < m_Width; ++x)
{
for (int y = 0; y < m_Height; ++y)
{
m_Tiles[x][y] = tiles[x][y].ToArray();
}
}
}
private MultiComponentList()
{
m_Tiles = new StaticTile[0][][];
m_List = new MultiTileEntry[0];
}
}
public class UOPHash
{
public static void BuildChunkIDs(ref Dictionary<ulong, int> chunkIds, ref Dictionary<ulong, int> chunkIds2)
{
int maxId;
string[] formats = GetHashFormat(0, out maxId);
for (int i = 0; i < maxId; ++i)
{
chunkIds[HashLittle2(String.Format(formats[0], i))] = i;
}
if (formats[1] != "")
{
for (int i = 0; i < maxId; ++i)
chunkIds2[HashLittle2(String.Format(formats[1], i))] = i;
}
}
private static string[] GetHashFormat(int typeIndex, out int maxId)
{
/*
* MaxID is only used for constructing a lookup table.
* Decrease to save some possibly unneeded computation.
*/
maxId = 0x10000;
return new string[] { "build/multicollection/{0:000000}.bin", "" };
}
private static ulong HashLittle2(string s)
{
int length = s.Length;
uint a, b, c;
a = b = c = 0xDEADBEEF + (uint)length;
int k = 0;
while (length > 12)
{
a += s[k];
a += ((uint)s[k + 1]) << 8;
a += ((uint)s[k + 2]) << 16;
a += ((uint)s[k + 3]) << 24;
b += s[k + 4];
b += ((uint)s[k + 5]) << 8;
b += ((uint)s[k + 6]) << 16;
b += ((uint)s[k + 7]) << 24;
c += s[k + 8];
c += ((uint)s[k + 9]) << 8;
c += ((uint)s[k + 10]) << 16;
c += ((uint)s[k + 11]) << 24;
a -= c; a ^= ((c << 4) | (c >> 28)); c += b;
b -= a; b ^= ((a << 6) | (a >> 26)); a += c;
c -= b; c ^= ((b << 8) | (b >> 24)); b += a;
a -= c; a ^= ((c << 16) | (c >> 16)); c += b;
b -= a; b ^= ((a << 19) | (a >> 13)); a += c;
c -= b; c ^= ((b << 4) | (b >> 28)); b += a;
length -= 12;
k += 12;
}
if (length != 0)
{
switch (length)
{
case 12: c += ((uint)s[k + 11]) << 24; goto case 11;
case 11: c += ((uint)s[k + 10]) << 16; goto case 10;
case 10: c += ((uint)s[k + 9]) << 8; goto case 9;
case 9: c += s[k + 8]; goto case 8;
case 8: b += ((uint)s[k + 7]) << 24; goto case 7;
case 7: b += ((uint)s[k + 6]) << 16; goto case 6;
case 6: b += ((uint)s[k + 5]) << 8; goto case 5;
case 5: b += s[k + 4]; goto case 4;
case 4: a += ((uint)s[k + 3]) << 24; goto case 3;
case 3: a += ((uint)s[k + 2]) << 16; goto case 2;
case 2: a += ((uint)s[k + 1]) << 8; goto case 1;
case 1: a += s[k]; break;
}
c ^= b; c -= ((b << 14) | (b >> 18));
a ^= c; a -= ((c << 11) | (c >> 21));
b ^= a; b -= ((a << 25) | (a >> 7));
c ^= b; c -= ((b << 16) | (b >> 16));
a ^= c; a -= ((c << 4) | (c >> 28));
b ^= a; b -= ((a << 14) | (a >> 18));
c ^= b; c -= ((b << 24) | (b >> 8));
}
return ((ulong)b << 32) | c;
}
}
}

73
Server/NativeReader.cs Normal file
View File

@@ -0,0 +1,73 @@
#region References
using System;
using System.Runtime.InteropServices;
using System.Threading;
#endregion
namespace Server
{
public static class NativeReader
{
private static readonly INativeReader m_NativeReader;
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 interface INativeReader
{
unsafe void Read(IntPtr ptr, void* buffer, int length);
}
public sealed class NativeReaderWin32 : INativeReader
{
internal class UnsafeNativeMethods
{
/*[DllImport("kernel32")]
internal unsafe static extern int _lread(IntPtr hFile, void* lpBuffer, int wBytes);*/
[DllImport("kernel32")]
internal static extern unsafe bool ReadFile(
IntPtr hFile,
void* lpBuffer,
uint nNumberOfBytesToRead,
ref uint lpNumberOfBytesRead,
NativeOverlapped* lpOverlapped);
}
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 static extern unsafe int read(IntPtr ptr, void* buffer, int length);
}
public unsafe void Read(IntPtr ptr, void* buffer, int length)
{
UnsafeNativeMethods.read(ptr, buffer, length);
}
}
}

View File

@@ -0,0 +1,108 @@
#region References
using System.Collections.Generic;
#endregion
namespace Server.Network
{
public class BufferPool
{
public static List<BufferPool> Pools { get; private set; }
static BufferPool()
{
Pools = new List<BufferPool>();
}
private readonly string m_Name;
private readonly int m_InitialCapacity;
private readonly int m_BufferSize;
private int m_Misses;
private readonly Queue<byte[]> m_FreeBuffers;
public int Count
{
get
{
lock (this)
return m_FreeBuffers.Count;
}
}
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;
m_InitialCapacity = initialCapacity;
m_BufferSize = bufferSize;
m_FreeBuffers = new Queue<byte[]>(initialCapacity);
for (int i = 0; i < initialCapacity; ++i)
{
m_FreeBuffers.Enqueue(new byte[bufferSize]);
}
lock (Pools)
Pools.Add(this);
}
public byte[] AcquireBuffer()
{
lock (this)
{
if (m_FreeBuffers.Count > 0)
{
return m_FreeBuffers.Dequeue();
}
++m_Misses;
for (int i = 0; i < m_InitialCapacity; ++i)
{
m_FreeBuffers.Enqueue(new byte[m_BufferSize]);
}
return m_FreeBuffers.Dequeue();
}
}
public void ReleaseBuffer(byte[] buffer)
{
if (buffer == null)
{
return;
}
lock (this)
m_FreeBuffers.Enqueue(buffer);
}
public void Free()
{
lock (Pools)
Pools.Remove(this);
}
}
}

147
Server/Network/ByteQueue.cs Normal file
View File

@@ -0,0 +1,147 @@
#region References
using System;
#endregion
namespace Server.Network
{
public class ByteQueue
{
private int m_Head;
private int m_Tail;
private int m_Size;
private byte[] m_Buffer;
public int Length { get { return m_Size; } }
public ByteQueue()
{
m_Buffer = new byte[2048];
}
public void Clear()
{
m_Head = 0;
m_Tail = 0;
m_Size = 0;
}
private void SetCapacity(int capacity)
{
var newBuffer = new byte[capacity];
if (m_Size > 0)
{
if (m_Head < m_Tail)
{
Buffer.BlockCopy(m_Buffer, m_Head, newBuffer, 0, m_Size);
}
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 = m_Size;
m_Buffer = newBuffer;
}
public byte GetPacketID()
{
if (m_Size >= 1)
{
return m_Buffer[m_Head];
}
return 0xFF;
}
public int GetPacketLength()
{
if (m_Size >= 3)
{
return (m_Buffer[(m_Head + 1) % m_Buffer.Length] << 8) | m_Buffer[(m_Head + 2) % m_Buffer.Length];
}
return 0;
}
public int Dequeue(byte[] buffer, int offset, int size)
{
if (size > m_Size)
{
size = m_Size;
}
if (size == 0)
{
return 0;
}
if (buffer != null)
{
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);
}
}
}
m_Head = (m_Head + size) % m_Buffer.Length;
m_Size -= size;
if (m_Size == 0)
{
m_Head = 0;
m_Tail = 0;
}
return size;
}
public void Enqueue(byte[] buffer, int offset, int size)
{
if ((m_Size + size) > m_Buffer.Length)
{
SetCapacity((m_Size + size + 2047) & ~2047);
}
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);
}
m_Tail = (m_Tail + size) % m_Buffer.Length;
m_Size += size;
}
}
}

View File

@@ -0,0 +1,394 @@
#region References
using System;
using System.Runtime.InteropServices;
#endregion
namespace Server.Network
{
/// <summary>
/// Handles outgoing packet compression for the network.
/// </summary>
public static class Compression
{
private static readonly 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 static unsafe void Compress(byte[] input, int offset, int count, byte[] output, ref int length)
{
if (input == null)
{
throw new ArgumentNullException("input");
}
else if (offset < 0 || offset >= input.Length)
{
throw new ArgumentOutOfRangeException("offset");
}
else if (count < 0 || count > input.Length)
{
throw new ArgumentOutOfRangeException("count");
}
else if ((input.Length - offset) < count)
{
throw new ArgumentException();
}
length = 0;
if (count > DefiniteOverflow)
{
return;
}
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);
return;
}
}
}
}
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("zlibwapi32")]
internal static extern string zlibVersion();
[DllImport("zlibwapi32")]
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
[DllImport("zlibwapi32")]
internal static extern ZLibError compress2(
byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
[DllImport("zlibwapi32")]
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
}
public string Version { get { return 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("zlibwapi64")]
internal static extern string zlibVersion();
[DllImport("zlibwapi64")]
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
[DllImport("zlibwapi64")]
internal static extern ZLibError compress2(
byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
[DllImport("zlibwapi64")]
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
}
public string Version { get { return 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 string Version { get { return 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 long destLength, byte[] source, long sourceLength);
[DllImport("libz")]
internal static extern ZLibError compress2(byte[] dest, ref long destLength, byte[] source, long sourceLength, ZLibQuality quality);
[DllImport("libz")]
internal static extern ZLibError uncompress(byte[] dest, ref long destLen, byte[] source, long sourceLen);
}
public string Version { get { return SafeNativeMethods.zlibVersion(); } }
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
{
long destLengthLong = 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)
{
long destLengthLong = 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)
{
long destLengthLong = destLength;
ZLibError z = SafeNativeMethods.uncompress(dest, ref destLengthLong, source, sourceLength);
destLength = (int)destLengthLong;
return z;
}
}
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
}
}

View File

@@ -0,0 +1,24 @@
namespace Server.Network
{
public delegate void OnEncodedPacketReceive(NetState state, IEntity ent, EncodedReader pvSrc);
public class EncodedPacketHandler
{
private readonly int m_PacketID;
private readonly bool m_Ingame;
private readonly OnEncodedPacketReceive m_OnReceive;
public EncodedPacketHandler(int packetID, bool ingame, OnEncodedPacketReceive onReceive)
{
m_PacketID = packetID;
m_Ingame = ingame;
m_OnReceive = onReceive;
}
public int PacketID { get { return m_PacketID; } }
public OnEncodedPacketReceive OnReceive { get { return m_OnReceive; } }
public bool Ingame { get { return m_Ingame; } }
}
}

View File

@@ -0,0 +1,63 @@
namespace Server.Network
{
public class EncodedReader
{
private readonly PacketReader m_Reader;
public EncodedReader(PacketReader reader)
{
m_Reader = reader;
}
public byte[] Buffer { get { return m_Reader.Buffer; } }
public void Trace(NetState state)
{
m_Reader.Trace(state);
}
public int ReadInt32()
{
if (m_Reader.ReadByte() != 0)
{
return 0;
}
return m_Reader.ReadInt32();
}
public Point3D ReadPoint3D()
{
if (m_Reader.ReadByte() != 3)
{
return Point3D.Zero;
}
return new Point3D(m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte());
}
public string ReadUnicodeStringSafe()
{
if (m_Reader.ReadByte() != 2)
{
return "";
}
int length = m_Reader.ReadUInt16();
return m_Reader.ReadUnicodeStringSafe(length);
}
public string ReadUnicodeString()
{
if (m_Reader.ReadByte() != 2)
{
return "";
}
int length = m_Reader.ReadUInt16();
return m_Reader.ReadUnicodeString(length);
}
}
}

280
Server/Network/Listener.cs Normal file
View File

@@ -0,0 +1,280 @@
#region References
using System;
using System.Collections;
using System.Collections.Generic;
using System.Net;
using System.Net.NetworkInformation;
using System.Net.Sockets;
using System.Threading;
#endregion
namespace Server.Network
{
public class Listener : IDisposable
{
private Socket m_Listener;
private PingListener _PingListener;
private readonly Queue<Socket> m_Accepted;
private readonly object m_AcceptedSyncRoot;
private readonly AsyncCallback m_OnAccept;
private static readonly Socket[] m_EmptySockets = new Socket[0];
public static IPEndPoint[] EndPoints { get; set; }
public Listener(IPEndPoint ipep)
{
m_Accepted = new Queue<Socket>();
m_AcceptedSyncRoot = ((ICollection)m_Accepted).SyncRoot;
m_Listener = Bind(ipep);
if (m_Listener == null)
{
return;
}
DisplayListener();
_PingListener = new PingListener(ipep);
m_OnAccept = OnAccept;
try
{
IAsyncResult res = m_Listener.BeginAccept(m_OnAccept, m_Listener);
}
catch (SocketException ex)
{
NetState.TraceException(ex);
}
catch (ObjectDisposedException)
{ }
}
private Socket Bind(IPEndPoint ipep)
{
Socket s = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
try
{
s.LingerState.Enabled = false;
// Default is 'false' starting Windows Vista and Server 2008. Source: https://msdn.microsoft.com/en-us/library/system.net.sockets.socket.exclusiveaddressuse(v=vs.110).aspx?f=255&MSPPError=-2147217396
s.ExclusiveAddressUse = false;
s.Bind(ipep);
s.Listen(8);
return s;
}
catch (Exception e)
{
if (e is SocketException)
{
SocketException se = (SocketException)e;
if (se.ErrorCode == 10048)
{
// WSAEADDRINUSE
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Listener Failed: {0}:{1} (In Use)", ipep.Address, ipep.Port);
Utility.PopColor();
}
else if (se.ErrorCode == 10049)
{
// WSAEADDRNOTAVAIL
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", ipep.Address, ipep.Port);
Utility.PopColor();
}
else
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Listener Exception:");
Console.WriteLine(e);
Utility.PopColor();
}
}
return null;
}
}
private void DisplayListener()
{
IPEndPoint ipep = m_Listener.LocalEndPoint as IPEndPoint;
if (ipep == null)
{
return;
}
if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any))
{
var adapters = NetworkInterface.GetAllNetworkInterfaces();
foreach (NetworkInterface adapter in adapters)
{
IPInterfaceProperties properties = adapter.GetIPProperties();
foreach (IPAddressInformation unicast in properties.UnicastAddresses)
{
if (ipep.AddressFamily == unicast.Address.AddressFamily)
{
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port);
Utility.PopColor();
}
}
}
/*
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
{
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port);
Utility.PopColor();
}
Utility.PushColor(ConsoleColor.DarkGreen);
Console.WriteLine(@"----------------------------------------------------------------------");
Utility.PopColor();
}
private void OnAccept(IAsyncResult asyncResult)
{
Socket listener = (Socket)asyncResult.AsyncState;
Socket accepted = null;
try
{
accepted = listener.EndAccept(asyncResult);
}
catch (SocketException ex)
{
NetState.TraceException(ex);
}
catch (ObjectDisposedException)
{
return;
}
if (accepted != null)
{
if (VerifySocket(accepted))
{
Enqueue(accepted);
}
else
{
Release(accepted);
}
}
try
{
listener.BeginAccept(m_OnAccept, listener);
}
catch (SocketException ex)
{
NetState.TraceException(ex);
}
catch (ObjectDisposedException)
{ }
}
private bool VerifySocket(Socket socket)
{
try
{
SocketConnectEventArgs args = new SocketConnectEventArgs(socket);
EventSink.InvokeSocketConnect(args);
return args.AllowConnection;
}
catch (Exception ex)
{
NetState.TraceException(ex);
return false;
}
}
private void Enqueue(Socket socket)
{
lock (m_AcceptedSyncRoot)
{
m_Accepted.Enqueue(socket);
}
Core.Set();
}
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);
}
}
public Socket[] Slice()
{
Socket[] array;
lock (m_AcceptedSyncRoot)
{
if (m_Accepted.Count == 0)
{
return m_EmptySockets;
}
array = m_Accepted.ToArray();
m_Accepted.Clear();
}
return array;
}
public void Dispose()
{
Socket socket = Interlocked.Exchange(ref m_Listener, null);
if (socket != null)
{
socket.Close();
}
if (_PingListener == null)
{
return;
}
_PingListener.Dispose();
_PingListener = null;
}
}
}

View File

@@ -0,0 +1,366 @@
#region References
using System;
using System.Collections.Generic;
using System.Net.Sockets;
using System.Threading;
using Server.Diagnostics;
#endregion
namespace Server.Network
{
public class MessagePump
{
private Queue<NetState> m_Queue;
private Queue<NetState> m_WorkingQueue;
private readonly Queue<NetState> m_Throttled;
public Listener[] Listeners { get; set; }
public MessagePump()
{
var ipep = Listener.EndPoints;
Listeners = new Listener[ipep.Length];
bool success = false;
do
{
for (int i = 0; i < ipep.Length; i++)
{
Listeners[i] = new Listener(ipep[i]);
success = true;
}
if (!success)
{
Utility.PushColor(ConsoleColor.Yellow);
Console.WriteLine("Retrying...");
Utility.PopColor();
Thread.Sleep(10000);
}
}
while (!success);
m_Queue = new Queue<NetState>();
m_WorkingQueue = new Queue<NetState>();
m_Throttled = new Queue<NetState>();
}
public void AddListener(Listener l)
{
var old = Listeners;
Listeners = new Listener[old.Length + 1];
for (int i = 0; i < old.Length; ++i)
{
Listeners[i] = old[i];
}
Listeners[old.Length] = l;
}
private void CheckListener()
{
foreach (Listener l in Listeners)
{
var accepted = l.Slice();
foreach (Socket s in accepted)
{
NetState ns = new NetState(s, this);
ns.Start();
if (ns.Running && Display(ns))
{
Utility.PushColor(ConsoleColor.Green);
Console.WriteLine("Client: {0}: Connected. [{1} Online]", ns, NetState.Instances.Count);
Utility.PopColor();
}
}
}
}
public static bool Display(NetState ns)
{
if (ns == null)
return false;
string state = ns.ToString();
foreach (var str in _NoDisplay)
{
if (str == state)
return false;
}
return true;
}
private static string[] _NoDisplay =
{
"192.99.10.155",
"192.99.69.21",
};
public void OnReceive(NetState ns)
{
lock (this)
m_Queue.Enqueue(ns);
Core.Set();
}
public void Slice()
{
CheckListener();
lock (this)
{
var temp = m_WorkingQueue;
m_WorkingQueue = m_Queue;
m_Queue = temp;
}
while (m_WorkingQueue.Count > 0)
{
NetState ns = m_WorkingQueue.Dequeue();
if (ns.Running)
{
HandleReceive(ns);
}
}
lock (this)
{
while (m_Throttled.Count > 0)
{
m_Queue.Enqueue(m_Throttled.Dequeue());
}
}
}
private const int BufferSize = 4096;
private readonly BufferPool m_Buffers = new BufferPool("Processor", 4, BufferSize);
public static 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)
{
var m_Peek = new byte[4];
buffer.Dequeue(m_Peek, 0, 4);
uint seed = (uint)((m_Peek[0] << 24) | (m_Peek[1] << 16) | (m_Peek[2] << 8) | m_Peek[3]);
if (seed == 0)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Login: {0}: Invalid Client", ns);
Utility.PopColor();
ns.Dispose();
return false;
}
ns.Seed = seed;
ns.Seeded = true;
return true;
}
return false;
}
public static bool CheckEncrypted(NetState ns, int packetID)
{
if (!ns.SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 &&
packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF && packetID != 0xE4 && packetID != 0xFF)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Encrypted Client Unsupported", ns);
Utility.PopColor();
ns.Dispose();
return true;
}
return false;
}
public void HandleReceive(NetState ns)
{
ByteQueue buffer = ns.Buffer;
if (buffer == null || buffer.Length <= 0)
{
return;
}
lock (buffer)
{
if (!ns.Seeded && !HandleSeed(ns, buffer))
{
return;
}
int length = buffer.Length;
while (length > 0 && ns.Running)
{
int packetID = buffer.GetPacketID();
if (CheckEncrypted(ns, packetID))
{
return;
}
PacketHandler handler = ns.GetHandler(packetID);
if (handler == null)
{
#if DEBUG
var data = new byte[length];
length = buffer.Dequeue(data, 0, length);
new PacketReader(data, length, false).Trace(ns);
#else
buffer.Dequeue(null, 0, length);
#endif
return;
}
int packetLength = handler.Length;
if (packetLength <= 0)
{
if (length >= 3)
{
packetLength = buffer.GetPacketLength();
if (packetLength < 3)
{
ns.Dispose();
return;
}
}
else
{
return;
}
}
if (length < packetLength)
{
return;
}
if (handler.Ingame)
{
if (ns.Mobile == null)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Packet (0x{1:X2}) Requires State Mobile", ns, packetID);
Utility.PopColor();
ns.Dispose();
return;
}
if (ns.Mobile.Deleted)
{
Utility.PushColor(ConsoleColor.Red);
Console.WriteLine("Client: {0}: Packet (0x{1:X2}) Ivalid State Mobile", ns, packetID);
Utility.PopColor();
ns.Dispose();
return;
}
}
ThrottlePacketCallback throttler = handler.ThrottleCallback;
if (throttler != null)
{
bool drop;
if (!throttler((byte)packetID, ns, out drop))
{
if (!drop)
{
m_Throttled.Enqueue(ns);
}
else
{
buffer.Dequeue(null, 0, packetLength);
}
return;
}
}
PacketReceiveProfile prof = null;
if (Core.Profiling)
{
prof = PacketReceiveProfile.Acquire(packetID);
}
if (prof != null)
{
prof.Start();
}
byte[] packetBuffer;
if (BufferSize >= packetLength)
{
packetBuffer = m_Buffers.AcquireBuffer();
}
else
{
packetBuffer = new byte[packetLength];
}
packetLength = buffer.Dequeue(packetBuffer, 0, packetLength);
if (packetBuffer != null && packetBuffer.Length > 0 && packetLength > 0)
{
PacketReader r = new PacketReader(packetBuffer, packetLength, handler.Length != 0);
handler.OnReceive(ns, r);
ns.SetPacketTime((byte)packetID);
if (BufferSize >= packetLength)
{
m_Buffers.ReleaseBuffer(packetBuffer);
}
}
if (prof != null)
{
prof.Finish(packetLength);
}
length = buffer.Length;
}
}
}
}
}

1335
Server/Network/NetState.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,32 @@
namespace Server.Network
{
public delegate void OnPacketReceive(NetState state, PacketReader pvSrc);
public delegate bool ThrottlePacketCallback(byte packetID, NetState state, out bool drop);
public class PacketHandler
{
private readonly int m_PacketID;
private readonly int m_Length;
private readonly bool m_Ingame;
private readonly OnPacketReceive m_OnReceive;
public PacketHandler(int packetID, int length, bool ingame, OnPacketReceive onReceive)
{
m_PacketID = packetID;
m_Length = length;
m_Ingame = ingame;
m_OnReceive = onReceive;
}
public int PacketID { get { return m_PacketID; } }
public int Length { get { return m_Length; } }
public OnPacketReceive OnReceive { get { return m_OnReceive; } }
public ThrottlePacketCallback ThrottleCallback { get; set; }
public bool Ingame { get { return m_Ingame; } }
}
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,511 @@
#region References
using System;
using System.IO;
using System.Text;
#endregion
namespace Server.Network
{
public class PacketReader
{
private readonly byte[] m_Data;
private readonly int m_Size;
private int m_Index;
public PacketReader(byte[] data, int size, bool fixedSize)
{
m_Data = data;
m_Size = size;
m_Index = fixedSize ? 1 : 3;
}
public byte[] Buffer { get { return m_Data; } }
public int Size { get { return m_Size; } }
public void Trace(NetState state)
{
try
{
using (StreamWriter sw = new StreamWriter("Packets.log", true))
{
var buffer = m_Data;
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 = m_Size - offset;
break;
}
return m_Index;
}
public int ReadInt32()
{
if ((m_Index + 4) > m_Size)
{
return 0;
}
return (m_Data[m_Index++] << 24) | (m_Data[m_Index++] << 16) | (m_Data[m_Index++] << 8) | m_Data[m_Index++];
}
public short ReadInt16()
{
if ((m_Index + 2) > m_Size)
{
return 0;
}
return (short)((m_Data[m_Index++] << 8) | m_Data[m_Index++]);
}
public byte ReadByte()
{
if ((m_Index + 1) > m_Size)
{
return 0;
}
return m_Data[m_Index++];
}
public uint ReadUInt32()
{
if ((m_Index + 4) > m_Size)
{
return 0;
}
return (uint)((m_Data[m_Index++] << 24) | (m_Data[m_Index++] << 16) | (m_Data[m_Index++] << 8) | m_Data[m_Index++]);
}
public ushort ReadUInt16()
{
if ((m_Index + 2) > m_Size)
{
return 0;
}
return (ushort)((m_Data[m_Index++] << 8) | m_Data[m_Index++]);
}
public sbyte ReadSByte()
{
if ((m_Index + 1) > m_Size)
{
return 0;
}
return (sbyte)m_Data[m_Index++];
}
public bool ReadBoolean()
{
if ((m_Index + 1) > m_Size)
{
return false;
}
return (m_Data[m_Index++] != 0);
}
public string ReadUnicodeStringLE()
{
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0)
{
sb.Append((char)c);
}
return sb.ToString();
}
public string ReadUnicodeStringLESafe(int fixedLength)
{
int bound = m_Index + (fixedLength << 1);
int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < bound && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
m_Index = end;
return sb.ToString();
}
public string ReadUnicodeStringLESafe()
{
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < m_Size && (c = (m_Data[m_Index++] | (m_Data[m_Index++] << 8))) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
return sb.ToString();
}
public string ReadUnicodeStringSafe()
{
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
return sb.ToString();
}
public string ReadUnicodeString()
{
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < m_Size && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0)
{
sb.Append((char)c);
}
return sb.ToString();
}
public bool IsSafeChar(int c)
{
return (c >= 0x20 && c < 0xFFFE);
}
public string ReadUTF8StringSafe(int fixedLength)
{
if (m_Index >= m_Size)
{
m_Index += fixedLength;
return String.Empty;
}
int bound = m_Index + fixedLength;
//int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
int count = 0;
int index = m_Index;
int start = m_Index;
while (index < bound && m_Data[index++] != 0)
{
++count;
}
index = 0;
var buffer = new byte[count];
int value = 0;
while (m_Index < bound && (value = m_Data[m_Index++]) != 0)
{
buffer[index++] = (byte)value;
}
string s = Utility.UTF8.GetString(buffer);
bool isSafe = true;
for (int i = 0; isSafe && i < s.Length; ++i)
{
isSafe = IsSafeChar(s[i]);
}
m_Index = start + fixedLength;
if (isSafe)
{
return s;
}
StringBuilder sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; ++i)
{
if (IsSafeChar(s[i]))
{
sb.Append(s[i]);
}
}
return sb.ToString();
}
public string ReadUTF8StringSafe()
{
if (m_Index >= m_Size)
{
return String.Empty;
}
int count = 0;
int index = m_Index;
while (index < m_Size && m_Data[index++] != 0)
{
++count;
}
index = 0;
var buffer = new byte[count];
int value = 0;
while (m_Index < m_Size && (value = m_Data[m_Index++]) != 0)
{
buffer[index++] = (byte)value;
}
string s = Utility.UTF8.GetString(buffer);
bool isSafe = true;
for (int i = 0; isSafe && i < s.Length; ++i)
{
isSafe = IsSafeChar(s[i]);
}
if (isSafe)
{
return s;
}
StringBuilder sb = new StringBuilder(s.Length);
for (int i = 0; i < s.Length; ++i)
{
if (IsSafeChar(s[i]))
{
sb.Append(s[i]);
}
}
return sb.ToString();
}
public string ReadUTF8String()
{
if (m_Index >= m_Size)
{
return String.Empty;
}
int count = 0;
int index = m_Index;
while (index < m_Size && m_Data[index++] != 0)
{
++count;
}
index = 0;
var buffer = new byte[count];
int value = 0;
while (m_Index < m_Size && (value = m_Data[m_Index++]) != 0)
{
buffer[index++] = (byte)value;
}
return Utility.UTF8.GetString(buffer);
}
public string ReadString()
{
StringBuilder sb = new StringBuilder();
int c;
while (m_Index < m_Size && (c = m_Data[m_Index++]) != 0)
{
sb.Append((char)c);
}
return sb.ToString();
}
public string ReadStringSafe()
{
StringBuilder sb = new StringBuilder();
int c;
while (m_Index < m_Size && (c = m_Data[m_Index++]) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
return sb.ToString();
}
public string ReadUnicodeStringSafe(int fixedLength)
{
int bound = m_Index + (fixedLength << 1);
int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
m_Index = end;
return sb.ToString();
}
public string ReadUnicodeString(int fixedLength)
{
int bound = m_Index + (fixedLength << 1);
int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
StringBuilder sb = new StringBuilder();
int c;
while ((m_Index + 1) < bound && (c = ((m_Data[m_Index++] << 8) | m_Data[m_Index++])) != 0)
{
sb.Append((char)c);
}
m_Index = end;
return sb.ToString();
}
public string ReadStringSafe(int fixedLength)
{
int bound = m_Index + fixedLength;
int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
StringBuilder sb = new StringBuilder();
int c;
while (m_Index < bound && (c = m_Data[m_Index++]) != 0)
{
if (IsSafeChar(c))
{
sb.Append((char)c);
}
}
m_Index = end;
return sb.ToString();
}
public string ReadString(int fixedLength)
{
int bound = m_Index + fixedLength;
int end = bound;
if (bound > m_Size)
{
bound = m_Size;
}
StringBuilder sb = new StringBuilder();
int c;
while (m_Index < bound && (c = m_Data[m_Index++]) != 0)
{
sb.Append((char)c);
}
m_Index = end;
return sb.ToString();
}
}
}

View File

@@ -0,0 +1,202 @@
using System;
using Server.Commands;
namespace Server.Network
{
public static class PacketThrottles
{
private static readonly int[] _Delays = new int[Byte.MaxValue];
private static readonly bool[] _Reserved = new bool[Byte.MaxValue];
static PacketThrottles()
{
_Delays[0x03] = 5; // speech
_Delays[0xAD] = 5; // speech
_Delays[0x32] = 5; // fly toggle
_Delays[0x72] = 5; // war toggle
_Delays[0x3B] = 100; // vendor buy response
_Delays[0x9F] = 100; // vendor sell response
_Delays[0xB8] = 100; // profile request
_Delays[0x6F] = 100; // trade request
_Delays[0x75] = 100; // rename request
_Delays[0x9B] = 100; // help request
_Delays[0xEC] = 100; // equip macro
_Delays[0xED] = 100; // unequip macro
#region Reserved
// Reserved packets cannot be overridden by this throttle system
_Reserved[0x02] = true; // movement request, see: PlayerMobile
_Reserved[0x80] = true; // login request, see: AccountAttackLimiter
_Reserved[0x91] = true; // login request, see: AccountAttackLimiter
_Reserved[0xCF] = true; // login request, see: AccountAttackLimiter
#endregion
}
public static void Configure()
{
EventSink.WorldLoad += () => Persistence.Deserialize("Saves/PacketThrottles.bin", Load);
EventSink.WorldSave += e => Persistence.Serialize("Saves/PacketThrottles.bin", Save);
CommandSystem.Register("GetThrottle", AccessLevel.Administrator, new CommandEventHandler(GetThrottle));
CommandSystem.Register("SetThrottle", AccessLevel.Administrator, new CommandEventHandler(SetThrottle));
}
public static void Initialize()
{
for (byte i = 0; i < Byte.MaxValue; i++)
{
if (!_Reserved[i] && _Delays[i] > 0)
{
PacketHandlers.RegisterThrottler(i, HandleThrottle);
}
}
}
private static void GetThrottle(CommandEventArgs e)
{
if (e.Length != 1)
{
e.Mobile.SendMessage("Usage: {0}GetThrottle <packetID>", CommandSystem.Prefix);
return;
}
var packetID = e.GetInt32(0);
if (packetID < Byte.MinValue || packetID > Byte.MaxValue)
{
e.Mobile.SendMessage("Usage: PacketID must be between {0} and {1} inclusive", Byte.MinValue, Byte.MaxValue);
return;
}
if (_Reserved[packetID])
{
e.Mobile.SendMessage("Packet 0x{0:X2} throttle is protected.");
}
else
{
e.Mobile.SendMessage("Packet 0x{0:X2} throttle is {1}ms", packetID, _Delays[packetID]);
}
}
private static void SetThrottle(CommandEventArgs e)
{
if (e.Length < 2)
{
e.Mobile.SendMessage("Usage: {0}SetThrottle <packetID> <delayMS>", CommandSystem.Prefix);
return;
}
var packetID = e.GetInt32(0);
var delay = e.GetInt32(1);
if (packetID < Byte.MinValue || packetID > Byte.MaxValue)
{
e.Mobile.SendMessage("Usage: PacketID must be between {0} and {1} inclusive", Byte.MinValue, Byte.MaxValue);
return;
}
if (_Reserved[packetID])
{
e.Mobile.SendMessage("Packet 0x{0:X2} throttle is protected and can not be set");
return;
}
if (delay < 0 || delay > 5000)
{
e.Mobile.SendMessage("Usage: Delay must be between 0 and 5000 inclusive");
return;
}
SetThrottle((byte)packetID, delay);
if (delay > 0)
{
e.Mobile.SendMessage("Packet 0x{0:X} throttle is {1}ms", packetID, _Delays[packetID]);
}
else
{
e.Mobile.SendMessage("Packet 0x{0:X} throttle has been removed", packetID, _Delays[packetID]);
}
}
public static int GetThrottle(byte packetID)
{
if (!_Reserved[packetID])
{
return _Delays[packetID];
}
return 0;
}
public static void SetThrottle(byte packetID, int delay)
{
if (_Reserved[packetID])
{
return;
}
delay = Math.Max(0, Math.Min(5000, delay));
var oldDelay = _Delays[packetID];
if (oldDelay <= 0 && delay > 0)
{
PacketHandlers.RegisterThrottler(packetID, HandleThrottle);
}
else if (oldDelay > 0 && delay <= 0)
{
PacketHandlers.RegisterThrottler(packetID, null);
}
_Delays[packetID] = delay;
}
private static bool HandleThrottle(byte packetID, NetState ns, out bool drop)
{
drop = false;
if (ns.Mobile == null || ns.Mobile.AccessLevel >= AccessLevel.Counselor)
{
return true;
}
if (ns.IsThrottled(packetID, _Delays[packetID]))
{
drop = true;
return false;
}
return true;
}
private static void Save(GenericWriter writer)
{
writer.WriteEncodedInt(0);
for (var i = 0; i < _Delays.Length; i++)
{
writer.WriteEncodedInt(_Delays[i]);
}
}
private static void Load(GenericReader reader)
{
reader.ReadEncodedInt();
for (var i = 0; i < _Delays.Length; i++)
{
_Delays[i] = reader.ReadEncodedInt();
}
}
}
}

View File

@@ -0,0 +1,439 @@
#region References
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
#endregion
namespace Server.Network
{
/// <summary>
/// Provides functionality for writing primitive binary data.
/// </summary>
public class PacketWriter
{
private static readonly 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 readonly MemoryStream m_Stream;
private int m_Capacity;
/// <summary>
/// Internal format buffer.
/// </summary>
private readonly 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 { get { return m_Stream.Length; } }
/// <summary>
/// Gets or sets the current stream position.
/// </summary>
public long Position { get { return m_Stream.Position; } set { m_Stream.Position = value; } }
/// <summary>
/// The internal stream used by this PacketWriter instance.
/// </summary>
public MemoryStream UnderlyingStream { get { return 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();
}
}
}

5492
Server/Network/Packets.cs Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,98 @@
#region References
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
#endregion
namespace Server.Network
{
public class PingListener : IDisposable
{
private UdpClient _Listener;
const int Port = 12000;
private static UdpClient Bind(IPEndPoint ipep)
{
ipep = new IPEndPoint(ipep.Address, Port);
var s = new UdpClient
{
Client = new Socket(ipep.AddressFamily, SocketType.Dgram, ProtocolType.Udp)
};
try
{
s.Client.ExclusiveAddressUse = false;
s.Client.Bind(ipep);
return s;
}
catch (SocketException e)
{
switch (e.ErrorCode)
{
case 10048: // WSAEADDRINUSE
Console.WriteLine("Ping Listener Failed: {0}:{1} (In Use)", ipep.Address, Port);
break;
case 10049: // WSAEADDRNOTAVAIL
Console.WriteLine("Ping Listener Failed: {0}:{1} (Unavailable)", ipep.Address, Port);
break;
default:
{
Console.WriteLine("Ping Listener Exception:");
Console.WriteLine(e);
}
break;
}
}
return null;
}
public PingListener(IPEndPoint ipep)
{
_Listener = Bind(ipep);
BeginReceive();
}
private void BeginReceive()
{
if (_Listener != null)
{
_Listener.BeginReceive(EndReceive, _Listener);
}
}
private void EndReceive(IAsyncResult r)
{
var ripep = new IPEndPoint(IPAddress.Any, Port);
var recvd = _Listener.EndReceive(r, ref ripep);
//Console.WriteLine("[PING]: \"{0}\" Received from {1}", Encoding.UTF8.GetString(recvd), ripep);
BeginSend(recvd, ripep);
BeginReceive();
}
private void BeginSend(byte[] data, IPEndPoint ipep)
{
//Console.WriteLine("[PONG]: \"{0}\" Sent to {1}", Encoding.UTF8.GetString(data), ipep);
_Listener.BeginSend(data, data.Length, ipep, EndSend, _Listener);
}
private void EndSend(IAsyncResult asyncResult)
{
_Listener.EndSend(asyncResult);
}
public void Dispose()
{
_Listener.Close();
_Listener = null;
}
}
}

239
Server/Network/SendQueue.cs Normal file
View File

@@ -0,0 +1,239 @@
#region References
using System;
using System.Collections.Generic;
#endregion
namespace Server.Network
{
public class SendQueue
{
public class Gram
{
private static readonly Stack<Gram> _pool = new Stack<Gram>();
public static Gram Acquire()
{
lock (_pool)
{
Gram gram;
if (_pool.Count > 0)
{
gram = _pool.Pop();
}
else
{
gram = new Gram();
}
gram._buffer = AcquireBuffer();
gram._length = 0;
return gram;
}
}
private byte[] _buffer;
private int _length;
public byte[] Buffer { get { return _buffer; } }
public int Length { get { return _length; } }
public int Available { get { return (_buffer.Length - _length); } }
public bool IsFull { get { return (_length == _buffer.Length); } }
private Gram()
{ }
public int Write(byte[] buffer, int offset, int length)
{
int write = Math.Min(length, Available);
System.Buffer.BlockCopy(buffer, offset, _buffer, _length, write);
_length += write;
return write;
}
public void Release()
{
lock (_pool)
{
_pool.Push(this);
ReleaseBuffer(_buffer);
}
}
}
private static int m_CoalesceBufferSize = 512;
private static BufferPool m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize);
public static int CoalesceBufferSize
{
get { return m_CoalesceBufferSize; }
set
{
if (m_CoalesceBufferSize == value)
{
return;
}
BufferPool old = m_UnusedBuffers;
lock (old)
{
if (m_UnusedBuffers != null)
{
m_UnusedBuffers.Free();
}
m_CoalesceBufferSize = value;
m_UnusedBuffers = new BufferPool("Coalesced", 2048, m_CoalesceBufferSize);
}
}
}
public static byte[] AcquireBuffer()
{
lock (m_UnusedBuffers)
return m_UnusedBuffers.AcquireBuffer();
}
public static void ReleaseBuffer(byte[] buffer)
{
lock (m_UnusedBuffers)
if (buffer != null && buffer.Length == m_CoalesceBufferSize)
{
m_UnusedBuffers.ReleaseBuffer(buffer);
}
}
private readonly Queue<Gram> _pending;
private Gram _buffered;
public bool IsFlushReady { get { return (_pending.Count == 0 && _buffered != null); } }
public bool IsEmpty { get { return (_pending.Count == 0 && _buffered == null); } }
public SendQueue()
{
_pending = new Queue<Gram>();
}
public Gram CheckFlushReady()
{
Gram gram = _buffered;
_pending.Enqueue(_buffered);
_buffered = null;
return gram;
}
public Gram Dequeue()
{
Gram gram = null;
if (_pending.Count > 0)
{
_pending.Dequeue().Release();
if (_pending.Count > 0)
{
gram = _pending.Peek();
}
}
return gram;
}
private const int PendingCap = 0x200000;
public Gram Enqueue(byte[] buffer, int length)
{
return Enqueue(buffer, 0, length);
}
public Gram Enqueue(byte[] buffer, int offset, int length)
{
if (buffer == null)
{
throw new ArgumentNullException("buffer");
}
else 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.");
}
else 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.");
}
else if ((buffer.Length - offset) < length)
{
throw new ArgumentException("Offset and length do not point to a valid segment within the buffer.");
}
int existingBytes = (_pending.Count * m_CoalesceBufferSize) + (_buffered == null ? 0 : _buffered.Length);
if ((existingBytes + length) > PendingCap)
{
throw new CapacityExceededException();
}
Gram gram = null;
while (length > 0)
{
if (_buffered == null)
{
// nothing yet buffered
_buffered = Gram.Acquire();
}
int bytesWritten = _buffered.Write(buffer, offset, length);
offset += bytesWritten;
length -= bytesWritten;
if (_buffered.IsFull)
{
if (_pending.Count == 0)
{
gram = _buffered;
}
_pending.Enqueue(_buffered);
_buffered = null;
}
}
return gram;
}
public void Clear()
{
if (_buffered != null)
{
_buffered.Release();
_buffered = null;
}
while (_pending.Count > 0)
{
_pending.Dequeue().Release();
}
}
}
[Serializable]
public sealed class CapacityExceededException : Exception
{
public CapacityExceededException()
: base("Too much data pending.")
{ }
}
}

36
Server/Notoriety.cs Normal file
View File

@@ -0,0 +1,36 @@
namespace Server
{
public delegate int NotorietyHandler(Mobile source, IDamageable 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 NotorietyHandler Handler { get; set; }
private static int[] m_Hues = {0x000, 0x059, 0x03F, 0x3B2, 0x3B2, 0x090, 0x022, 0x035};
public static int[] Hues { get { return m_Hues; } set { m_Hues = value; } }
public static int GetHue(int noto)
{
if (noto < 0 || noto >= m_Hues.Length)
{
return 0;
}
return m_Hues[noto];
}
public static int Compute(Mobile source, IDamageable target)
{
return Handler == null ? CanBeAttacked : Handler(source, target);
}
}
}

Some files were not shown because too many files have changed in this diff Show More