Reorganizes Project (#41)
This commit is contained in:
parent
08bf44af9a
commit
3614a66aee
3499 changed files with 79 additions and 55 deletions
205
Projects/Server/AggressorInfo.cs
Normal file
205
Projects/Server/AggressorInfo.cs
Normal file
|
|
@ -0,0 +1,205 @@
|
|||
/***************************************************************************
|
||||
* AggressorInfo.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class AggressorInfo
|
||||
{
|
||||
private static Queue<AggressorInfo> m_Pool = new Queue<AggressorInfo>();
|
||||
private Mobile m_Attacker, m_Defender;
|
||||
private bool m_CanReportMurder;
|
||||
private bool m_CriminalAggression;
|
||||
private DateTime m_LastCombatTime;
|
||||
|
||||
private bool m_Queued;
|
||||
private bool m_Reported;
|
||||
|
||||
private AggressorInfo(Mobile attacker, Mobile defender, bool criminal)
|
||||
{
|
||||
m_Attacker = attacker;
|
||||
m_Defender = defender;
|
||||
|
||||
m_CanReportMurder = criminal;
|
||||
m_CriminalAggression = criminal;
|
||||
|
||||
Refresh();
|
||||
}
|
||||
|
||||
public static TimeSpan ExpireDelay{ get; set; } = TimeSpan.FromMinutes(2.0);
|
||||
|
||||
public bool Expired
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
return m_Attacker.Deleted || m_Defender.Deleted || DateTime.UtcNow >= m_LastCombatTime + 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 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);
|
||||
}
|
||||
|
||||
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 void Refresh()
|
||||
{
|
||||
if (m_Queued)
|
||||
DumpAccess();
|
||||
|
||||
m_LastCombatTime = DateTime.UtcNow;
|
||||
m_Reported = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
BIN
Projects/Server/Assemblies/System.IO.Pipelines.dll
Normal file
BIN
Projects/Server/Assemblies/System.IO.Pipelines.dll
Normal file
Binary file not shown.
BIN
Projects/Server/Assemblies/rdrand.so
Executable file
BIN
Projects/Server/Assemblies/rdrand.so
Executable file
Binary file not shown.
BIN
Projects/Server/Assemblies/rdrand32.dll
Normal file
BIN
Projects/Server/Assemblies/rdrand32.dll
Normal file
Binary file not shown.
BIN
Projects/Server/Assemblies/rdrand64.dll
Normal file
BIN
Projects/Server/Assemblies/rdrand64.dll
Normal file
Binary file not shown.
BIN
Projects/Server/Assemblies/zlib32.dll
Normal file
BIN
Projects/Server/Assemblies/zlib32.dll
Normal file
Binary file not shown.
BIN
Projects/Server/Assemblies/zlib64.dll
Normal file
BIN
Projects/Server/Assemblies/zlib64.dll
Normal file
Binary file not shown.
165
Projects/Server/Attributes.cs
Normal file
165
Projects/Server/Attributes.cs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/***************************************************************************
|
||||
* Attributes.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class HueAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class BodyAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class PropertyObjectAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class NoSortAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class CallPriorityAttribute : Attribute
|
||||
{
|
||||
public CallPriorityAttribute(int priority)
|
||||
{
|
||||
Priority = priority;
|
||||
}
|
||||
|
||||
public int Priority{ get; set; }
|
||||
}
|
||||
|
||||
public class CallPriorityComparer : IComparer<MethodInfo>
|
||||
{
|
||||
public int Compare(MethodInfo x, MethodInfo y)
|
||||
{
|
||||
if (x == null && y == null)
|
||||
return 0;
|
||||
|
||||
if (x == null)
|
||||
return 1;
|
||||
|
||||
if (y == null)
|
||||
return -1;
|
||||
|
||||
int xPriority = GetPriority(x);
|
||||
int yPriority = GetPriority(y);
|
||||
|
||||
if (xPriority > yPriority)
|
||||
return 1;
|
||||
|
||||
if (xPriority < yPriority)
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private int GetPriority(MethodInfo mi)
|
||||
{
|
||||
object[] objs = mi.GetCustomAttributes(typeof(CallPriorityAttribute), true);
|
||||
|
||||
if (objs.Length == 0)
|
||||
return 0;
|
||||
|
||||
if (!(objs[0] is CallPriorityAttribute attr))
|
||||
return 0;
|
||||
|
||||
return attr.Priority;
|
||||
}
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class)]
|
||||
public class TypeAliasAttribute : Attribute
|
||||
{
|
||||
public TypeAliasAttribute(params string[] aliases)
|
||||
{
|
||||
Aliases = aliases;
|
||||
}
|
||||
|
||||
public string[] Aliases{ get; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct)]
|
||||
public class ParsableAttribute : Attribute
|
||||
{
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Enum)]
|
||||
public class CustomEnumAttribute : Attribute
|
||||
{
|
||||
public CustomEnumAttribute(string[] names)
|
||||
{
|
||||
Names = names;
|
||||
}
|
||||
|
||||
public string[] Names{ get; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Constructor)]
|
||||
public class ConstructibleAttribute : Attribute
|
||||
{
|
||||
public ConstructibleAttribute() :
|
||||
this(AccessLevel.Player) //Lowest accesslevel for current functionality (Level determined by access to [add)
|
||||
{
|
||||
}
|
||||
|
||||
public ConstructibleAttribute(AccessLevel accessLevel)
|
||||
{
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
|
||||
public AccessLevel AccessLevel{ get; set; }
|
||||
}
|
||||
|
||||
[AttributeUsage(AttributeTargets.Property)]
|
||||
public class CommandPropertyAttribute : Attribute
|
||||
{
|
||||
public CommandPropertyAttribute(AccessLevel level, bool readOnly)
|
||||
{
|
||||
ReadLevel = level;
|
||||
ReadOnly = readOnly;
|
||||
}
|
||||
|
||||
public CommandPropertyAttribute(AccessLevel level) : this(level, level)
|
||||
{
|
||||
}
|
||||
|
||||
public CommandPropertyAttribute(AccessLevel readLevel, AccessLevel writeLevel)
|
||||
{
|
||||
ReadLevel = readLevel;
|
||||
WriteLevel = writeLevel;
|
||||
}
|
||||
|
||||
public AccessLevel ReadLevel{ get; }
|
||||
|
||||
public AccessLevel WriteLevel{ get; }
|
||||
|
||||
public bool ReadOnly{ get; }
|
||||
}
|
||||
}
|
||||
106
Projects/Server/BaseVendor.cs
Normal file
106
Projects/Server/BaseVendor.cs
Normal file
|
|
@ -0,0 +1,106 @@
|
|||
/***************************************************************************
|
||||
* BaseVendor.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.Collections.Generic;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public class BuyItemStateComparer : IComparer<BuyItemState>
|
||||
{
|
||||
public int Compare(BuyItemState l, BuyItemState r)
|
||||
{
|
||||
if (l == null && r == null) return 0;
|
||||
if (l == null) return -1;
|
||||
if (r == null) return 1;
|
||||
|
||||
return l.MySerial.CompareTo(r.MySerial);
|
||||
}
|
||||
}
|
||||
|
||||
public class BuyItemResponse
|
||||
{
|
||||
public BuyItemResponse(Serial serial, int amount)
|
||||
{
|
||||
Serial = serial;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Serial Serial{ get; }
|
||||
|
||||
public int Amount{ get; }
|
||||
}
|
||||
|
||||
public class SellItemResponse
|
||||
{
|
||||
public SellItemResponse(Item i, int amount)
|
||||
{
|
||||
Item = i;
|
||||
Amount = amount;
|
||||
}
|
||||
|
||||
public Item Item{ get; }
|
||||
|
||||
public int Amount{ get; }
|
||||
}
|
||||
|
||||
public class SellItemState
|
||||
{
|
||||
public SellItemState(Item item, int price, string name)
|
||||
{
|
||||
Item = item;
|
||||
Price = price;
|
||||
Name = name;
|
||||
}
|
||||
|
||||
public Item Item{ get; }
|
||||
|
||||
public int Price{ get; }
|
||||
|
||||
public string Name{ get; }
|
||||
}
|
||||
|
||||
public class BuyItemState
|
||||
{
|
||||
public BuyItemState(string name, Serial cont, Serial serial, int price, int amount, int itemID, int hue)
|
||||
{
|
||||
Description = name;
|
||||
ContainerSerial = cont;
|
||||
MySerial = serial;
|
||||
Price = price;
|
||||
Amount = amount;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
public int Price{ get; }
|
||||
|
||||
public Serial MySerial{ get; }
|
||||
|
||||
public Serial ContainerSerial{ get; }
|
||||
|
||||
public int ItemID{ get; }
|
||||
|
||||
public int Amount{ get; }
|
||||
|
||||
public int Hue{ get; }
|
||||
|
||||
public string Description{ get; }
|
||||
}
|
||||
}
|
||||
206
Projects/Server/Body.cs
Normal file
206
Projects/Server/Body.cs
Normal file
|
|
@ -0,0 +1,206 @@
|
|||
/***************************************************************************
|
||||
* Body.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum BodyType : byte
|
||||
{
|
||||
Empty,
|
||||
Monster,
|
||||
Sea,
|
||||
Animal,
|
||||
Human,
|
||||
Equipment
|
||||
}
|
||||
|
||||
public struct Body
|
||||
{
|
||||
private static BodyType[] m_Types;
|
||||
|
||||
static Body()
|
||||
{
|
||||
if (File.Exists("Data/bodyTable.cfg"))
|
||||
{
|
||||
using (StreamReader ip = new StreamReader("Data/bodyTable.cfg"))
|
||||
{
|
||||
m_Types = new BodyType[0x1000];
|
||||
|
||||
string line;
|
||||
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
{
|
||||
if (line.Length == 0 || line.StartsWith("#"))
|
||||
continue;
|
||||
|
||||
string[] split = line.Split('\t');
|
||||
|
||||
if (int.TryParse(split[0], out int bodyID) && Enum.TryParse(split[1], true, out BodyType 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)
|
||||
{
|
||||
BodyID = bodyID;
|
||||
}
|
||||
|
||||
public BodyType Type => BodyID >= 0 && BodyID < m_Types.Length ? m_Types[BodyID] : BodyType.Empty;
|
||||
|
||||
public bool IsHuman => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Human
|
||||
&& BodyID != 402
|
||||
&& BodyID != 403
|
||||
&& BodyID != 607
|
||||
&& BodyID != 608
|
||||
&& BodyID != 694
|
||||
&& BodyID != 695
|
||||
&& BodyID != 970;
|
||||
|
||||
public bool IsGargoyle => BodyID == 666
|
||||
|| BodyID == 667
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695;
|
||||
|
||||
public bool IsMale => BodyID == 183
|
||||
|| BodyID == 185
|
||||
|| BodyID == 400
|
||||
|| BodyID == 402
|
||||
|| BodyID == 605
|
||||
|| BodyID == 607
|
||||
|| BodyID == 666
|
||||
|| BodyID == 694
|
||||
|| BodyID == 750;
|
||||
|
||||
public bool IsFemale => BodyID == 184
|
||||
|| BodyID == 186
|
||||
|| BodyID == 401
|
||||
|| BodyID == 403
|
||||
|| BodyID == 606
|
||||
|| BodyID == 608
|
||||
|| BodyID == 667
|
||||
|| BodyID == 695
|
||||
|| BodyID == 751;
|
||||
|
||||
public bool IsGhost => BodyID == 402
|
||||
|| BodyID == 403
|
||||
|| BodyID == 607
|
||||
|| BodyID == 608
|
||||
|| BodyID == 694
|
||||
|| BodyID == 695
|
||||
|| BodyID == 970;
|
||||
|
||||
public bool IsMonster => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Monster;
|
||||
|
||||
public bool IsAnimal => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Animal;
|
||||
|
||||
public bool IsEmpty => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Empty;
|
||||
|
||||
public bool IsSea => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Sea;
|
||||
|
||||
public bool IsEquipment => BodyID >= 0
|
||||
&& BodyID < m_Types.Length
|
||||
&& m_Types[BodyID] == BodyType.Equipment;
|
||||
|
||||
public int BodyID{ get; }
|
||||
|
||||
public static implicit operator int(Body a)
|
||||
{
|
||||
return a.BodyID;
|
||||
}
|
||||
|
||||
public static implicit operator Body(int a)
|
||||
{
|
||||
return new Body(a);
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{BodyID:X}";
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return BodyID.GetHashCode();
|
||||
}
|
||||
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
return o is Body b && b.BodyID == BodyID;
|
||||
}
|
||||
|
||||
public static bool operator ==(Body l, Body r)
|
||||
{
|
||||
return l.BodyID == r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator !=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID != r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator >(Body l, Body r)
|
||||
{
|
||||
return l.BodyID > r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator >=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID >= r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator <(Body l, Body r)
|
||||
{
|
||||
return l.BodyID < r.BodyID;
|
||||
}
|
||||
|
||||
public static bool operator <=(Body l, Body r)
|
||||
{
|
||||
return l.BodyID <= r.BodyID;
|
||||
}
|
||||
}
|
||||
}
|
||||
237
Projects/Server/ClientVersion.cs
Normal file
237
Projects/Server/ClientVersion.cs
Normal file
|
|
@ -0,0 +1,237 @@
|
|||
/***************************************************************************
|
||||
* ClientVersion.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public enum ClientType
|
||||
{
|
||||
Regular,
|
||||
UOTD,
|
||||
God,
|
||||
SA
|
||||
}
|
||||
|
||||
public class ClientVersion : IComparable<ClientVersion>, IComparer<ClientVersion>
|
||||
{
|
||||
public ClientVersion(int maj, int min, int rev, int pat, ClientType type = ClientType.Regular)
|
||||
{
|
||||
Major = maj;
|
||||
Minor = min;
|
||||
Revision = rev;
|
||||
Patch = pat;
|
||||
Type = type;
|
||||
|
||||
SourceString = _ToStringImpl();
|
||||
}
|
||||
|
||||
public ClientVersion(string fmt)
|
||||
{
|
||||
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++;
|
||||
|
||||
Major = Utility.ToInt32(fmt.Substring(0, br1));
|
||||
Minor = Utility.ToInt32(fmt.Substring(br1 + 1, br2 - br1 - 1));
|
||||
Revision = Utility.ToInt32(fmt.Substring(br2 + 1, br3 - br2 - 1));
|
||||
|
||||
if (br3 < fmt.Length)
|
||||
{
|
||||
if (Major <= 5 && Minor <= 0 && Revision <= 6) //Anything before 5.0.7
|
||||
{
|
||||
if (!char.IsWhiteSpace(fmt, br3))
|
||||
Patch = fmt[br3] - 'a' + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
Patch = Utility.ToInt32(fmt.Substring(br3 + 1, fmt.Length - br3 - 1));
|
||||
}
|
||||
}
|
||||
|
||||
if (fmt.IndexOf("god") >= 0 || fmt.IndexOf("gq") >= 0)
|
||||
Type = ClientType.God;
|
||||
else if (fmt.IndexOf("third dawn") >= 0 || fmt.IndexOf("uo:td") >= 0 || fmt.IndexOf("uotd") >= 0 ||
|
||||
fmt.IndexOf("uo3d") >= 0 || fmt.IndexOf("uo:3d") >= 0)
|
||||
Type = ClientType.UOTD;
|
||||
else
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
catch
|
||||
{
|
||||
Major = 0;
|
||||
Minor = 0;
|
||||
Revision = 0;
|
||||
Patch = 0;
|
||||
Type = ClientType.Regular;
|
||||
}
|
||||
}
|
||||
|
||||
public int Major{ get; }
|
||||
|
||||
public int Minor{ get; }
|
||||
|
||||
public int Revision{ get; }
|
||||
|
||||
public int Patch{ get; }
|
||||
|
||||
public ClientType Type{ get; }
|
||||
|
||||
public string SourceString{ get; }
|
||||
|
||||
public int CompareTo(ClientVersion o)
|
||||
{
|
||||
if (o == null)
|
||||
return 1;
|
||||
|
||||
if (Major > o.Major)
|
||||
return 1;
|
||||
if (Major < o.Major)
|
||||
return -1;
|
||||
if (Minor > o.Minor)
|
||||
return 1;
|
||||
if (Minor < o.Minor)
|
||||
return -1;
|
||||
if (Revision > o.Revision)
|
||||
return 1;
|
||||
if (Revision < o.Revision)
|
||||
return -1;
|
||||
if (Patch > o.Patch)
|
||||
return 1;
|
||||
if (Patch < o.Patch)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
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 Major ^ Minor ^ Revision ^ Patch ^ (int)Type;
|
||||
}
|
||||
|
||||
int IComparer<ClientVersion>.Compare(ClientVersion x, ClientVersion y)
|
||||
{
|
||||
return Compare(x, y);
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
ClientVersion v = obj as ClientVersion;
|
||||
|
||||
return Major == v?.Major
|
||||
&& Minor == v.Minor
|
||||
&& Revision == v.Revision
|
||||
&& Patch == v.Patch
|
||||
&& Type == v.Type;
|
||||
}
|
||||
|
||||
private string _ToStringImpl()
|
||||
{
|
||||
StringBuilder builder = new StringBuilder(16);
|
||||
|
||||
builder.Append(Major);
|
||||
builder.Append('.');
|
||||
builder.Append(Minor);
|
||||
builder.Append('.');
|
||||
builder.Append(Revision);
|
||||
|
||||
if (Major <= 5 && Minor <= 0 && Revision <= 6) //Anything before 5.0.7
|
||||
{
|
||||
if (Patch > 0)
|
||||
builder.Append((char)('a' + (Patch - 1)));
|
||||
}
|
||||
else
|
||||
{
|
||||
builder.Append('.');
|
||||
builder.Append(Patch);
|
||||
}
|
||||
|
||||
if (Type != ClientType.Regular)
|
||||
{
|
||||
builder.Append(' ');
|
||||
builder.Append(Type.ToString());
|
||||
}
|
||||
|
||||
return builder.ToString();
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return _ToStringImpl();
|
||||
}
|
||||
|
||||
public static bool IsNull(object x)
|
||||
{
|
||||
return ReferenceEquals(x, null);
|
||||
}
|
||||
|
||||
public static int Compare(ClientVersion a, ClientVersion b)
|
||||
{
|
||||
if (IsNull(a) && IsNull(b))
|
||||
return 0;
|
||||
if (IsNull(a))
|
||||
return -1;
|
||||
if (IsNull(b))
|
||||
return 1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
}
|
||||
}
|
||||
}
|
||||
242
Projects/Server/Commands.cs
Normal file
242
Projects/Server/Commands.cs
Normal file
|
|
@ -0,0 +1,242 @@
|
|||
/***************************************************************************
|
||||
* Commands.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public delegate void CommandEventHandler(CommandEventArgs e);
|
||||
|
||||
public class CommandEventArgs : EventArgs
|
||||
{
|
||||
public CommandEventArgs(Mobile mobile, string command, string argString, string[] arguments)
|
||||
{
|
||||
Mobile = mobile;
|
||||
Command = command;
|
||||
ArgString = argString;
|
||||
Arguments = arguments;
|
||||
}
|
||||
|
||||
public Mobile Mobile{ get; }
|
||||
|
||||
public string Command{ get; }
|
||||
|
||||
public string ArgString{ get; }
|
||||
|
||||
public string[] Arguments{ get; }
|
||||
|
||||
public int Length => Arguments.Length;
|
||||
|
||||
public string GetString(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return "";
|
||||
|
||||
return Arguments[index];
|
||||
}
|
||||
|
||||
public int GetInt32(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return 0;
|
||||
|
||||
return Utility.ToInt32(Arguments[index]);
|
||||
}
|
||||
|
||||
public uint GetUInt32(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return 0;
|
||||
|
||||
return Utility.ToUInt32(Arguments[index]);
|
||||
}
|
||||
|
||||
public bool GetBoolean(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return false;
|
||||
|
||||
return Utility.ToBoolean(Arguments[index]);
|
||||
}
|
||||
|
||||
public double GetDouble(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return 0.0;
|
||||
|
||||
return Utility.ToDouble(Arguments[index]);
|
||||
}
|
||||
|
||||
public TimeSpan GetTimeSpan(int index)
|
||||
{
|
||||
if (index < 0 || index >= Arguments.Length)
|
||||
return TimeSpan.Zero;
|
||||
|
||||
return Utility.ToTimeSpan(Arguments[index]);
|
||||
}
|
||||
}
|
||||
|
||||
public class CommandEntry : IComparable<CommandEntry>
|
||||
{
|
||||
public CommandEntry(string command, CommandEventHandler handler, AccessLevel accessLevel)
|
||||
{
|
||||
Command = command;
|
||||
Handler = handler;
|
||||
AccessLevel = accessLevel;
|
||||
}
|
||||
|
||||
public string Command{ get; }
|
||||
|
||||
public CommandEventHandler Handler{ get; }
|
||||
|
||||
public AccessLevel AccessLevel{ get; }
|
||||
|
||||
public int CompareTo(CommandEntry e)
|
||||
{
|
||||
return e == null ? 1 : Command.CompareTo(e.Command);
|
||||
}
|
||||
}
|
||||
|
||||
public static class CommandSystem
|
||||
{
|
||||
public static string Prefix{ get; set; } = "[";
|
||||
|
||||
public static Dictionary<string, CommandEntry> Entries{ get; } =
|
||||
new Dictionary<string, CommandEntry>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
public static AccessLevel BadCommandIgnoreLevel{ get; set; } = AccessLevel.Player;
|
||||
|
||||
public static string[] Split(string value)
|
||||
{
|
||||
char[] array = value.ToCharArray();
|
||||
List<string> list = new List<string>();
|
||||
|
||||
int start = 0;
|
||||
|
||||
while (start < array.Length)
|
||||
{
|
||||
char c = array[start];
|
||||
|
||||
if (c == '"')
|
||||
{
|
||||
++start;
|
||||
int 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 != ' ')
|
||||
{
|
||||
int 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();
|
||||
}
|
||||
|
||||
public static void Register(string command, AccessLevel access, CommandEventHandler handler)
|
||||
{
|
||||
Entries[command] = new CommandEntry(command, handler, access);
|
||||
}
|
||||
|
||||
public static bool Handle(Mobile from, string text, MessageType type = MessageType.Regular)
|
||||
{
|
||||
if (!text.StartsWith(Prefix) && type != MessageType.Command)
|
||||
return false;
|
||||
|
||||
if (type != MessageType.Command)
|
||||
text = text.Substring(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];
|
||||
}
|
||||
|
||||
Entries.TryGetValue(command, out CommandEntry entry);
|
||||
|
||||
if (entry != null)
|
||||
{
|
||||
if (from.AccessLevel >= entry.AccessLevel)
|
||||
{
|
||||
if (entry.Handler != null)
|
||||
{
|
||||
CommandEventArgs e = new CommandEventArgs(from, command, argString, args);
|
||||
entry.Handler(e);
|
||||
EventSink.InvokeCommand(e);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
||||
return false;
|
||||
|
||||
from.SendMessage("You do not have access to that command.");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (from.AccessLevel <= BadCommandIgnoreLevel)
|
||||
return false;
|
||||
|
||||
from.SendMessage("That is not a valid command.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
93
Projects/Server/ContextMenus/ContextMenu.cs
Normal file
93
Projects/Server/ContextMenus/ContextMenu.cs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
/***************************************************************************
|
||||
* ContextMenu.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.Collections.Generic;
|
||||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents the state of an active context menu. This includes who opened the menu, the menu's focus object, and a list of
|
||||
/// <see cref="ContextMenuEntry">entries</see> that the menu is composed of.
|
||||
/// <seealso cref="ContextMenuEntry" />
|
||||
/// </summary>
|
||||
public class ContextMenu
|
||||
{
|
||||
/// <summary>
|
||||
/// Instantiates a new ContextMenu instance.
|
||||
/// </summary>
|
||||
/// <param name="from">
|
||||
/// The <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// <seealso cref="From" />
|
||||
/// </param>
|
||||
/// <param name="target">
|
||||
/// The <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// <seealso cref="Target" />
|
||||
/// </param>
|
||||
public ContextMenu(Mobile from, object target)
|
||||
{
|
||||
From = from;
|
||||
Target = target;
|
||||
|
||||
List<ContextMenuEntry> list = new List<ContextMenuEntry>();
|
||||
|
||||
if (target is Mobile mobile)
|
||||
mobile.GetContextMenuEntries(from, list);
|
||||
else if (target is Item item)
|
||||
item.GetContextMenuEntries(from, list);
|
||||
|
||||
//m_Entries = (ContextMenuEntry[])list.ToArray( typeof( ContextMenuEntry ) );
|
||||
|
||||
Entries = list.ToArray();
|
||||
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
Entries[i].Owner = this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the <see cref="Mobile" /> who opened this ContextMenu.
|
||||
/// </summary>
|
||||
public Mobile From{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets an object of the <see cref="Mobile" /> or <see cref="Item" /> for which this ContextMenu is on.
|
||||
/// </summary>
|
||||
public object Target{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the list of <see cref="ContextMenuEntry">entries</see> contained in this ContextMenu.
|
||||
/// </summary>
|
||||
public ContextMenuEntry[] Entries{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Returns true if this ContextMenu requires packet version 2.
|
||||
/// </summary>
|
||||
public bool RequiresNewPacket
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = 0; i < Entries.Length; ++i)
|
||||
if (Entries[i].Number < 3000000 || Entries[i].Number > 3032767)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
98
Projects/Server/ContextMenus/ContextMenuEntry.cs
Normal file
98
Projects/Server/ContextMenus/ContextMenuEntry.cs
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
/***************************************************************************
|
||||
* ContextMenuEntry.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 Server.Network;
|
||||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a single entry of a <see cref="ContextMenu">context menu</see>.
|
||||
/// <seealso cref="ContextMenu" />
|
||||
/// </summary>
|
||||
public class ContextMenuEntry
|
||||
{
|
||||
/// <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 = -1)
|
||||
{
|
||||
if (number <= 0x7FFF) // Legacy code support
|
||||
Number = 3000000 + number;
|
||||
else
|
||||
Number = number;
|
||||
|
||||
Range = range;
|
||||
Enabled = true;
|
||||
Color = 0xFFFF;
|
||||
}
|
||||
|
||||
/// <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 => false;
|
||||
|
||||
/// <summary>
|
||||
/// Overridable. Virtual event invoked when the entry is clicked.
|
||||
/// </summary>
|
||||
public virtual void OnClick()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
37
Projects/Server/ContextMenus/OpenBackpackEntry.cs
Normal file
37
Projects/Server/ContextMenus/OpenBackpackEntry.cs
Normal file
|
|
@ -0,0 +1,37 @@
|
|||
/***************************************************************************
|
||||
* OpenBackpackEntry.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
public class OpenBackpackEntry : ContextMenuEntry
|
||||
{
|
||||
private Mobile m_Mobile;
|
||||
|
||||
public OpenBackpackEntry(Mobile m) : base(6145)
|
||||
{
|
||||
m_Mobile = m;
|
||||
}
|
||||
|
||||
public override void OnClick()
|
||||
{
|
||||
m_Mobile.Use(m_Mobile.Backpack);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
Projects/Server/ContextMenus/PaperdollEntry.cs
Normal file
38
Projects/Server/ContextMenus/PaperdollEntry.cs
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
/***************************************************************************
|
||||
* PaperdollEntry.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.ContextMenus
|
||||
{
|
||||
public class PaperdollEntry : ContextMenuEntry
|
||||
{
|
||||
private 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
88
Projects/Server/Diagnostics/BaseProfile.cs
Normal file
88
Projects/Server/Diagnostics/BaseProfile.cs
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public abstract class BaseProfile
|
||||
{
|
||||
private Stopwatch _stopwatch;
|
||||
|
||||
protected BaseProfile(string name)
|
||||
{
|
||||
Name = name;
|
||||
|
||||
_stopwatch = new Stopwatch();
|
||||
}
|
||||
|
||||
public string Name{ get; }
|
||||
|
||||
public long Count{ get; private set; }
|
||||
|
||||
public TimeSpan AverageTime => TimeSpan.FromTicks(TotalTime.Ticks / Math.Max(1, Count));
|
||||
|
||||
public TimeSpan PeakTime{ get; private set; }
|
||||
|
||||
public TimeSpan TotalTime{ get; private set; }
|
||||
|
||||
public static void WriteAll<T>(TextWriter op, IEnumerable<T> profiles) where T : BaseProfile
|
||||
{
|
||||
List<T> list = new List<T>(profiles);
|
||||
|
||||
list.Sort(delegate(T a, T b) { return -a.TotalTime.CompareTo(b.TotalTime); });
|
||||
|
||||
foreach (T prof in list)
|
||||
{
|
||||
prof.WriteTo(op);
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Projects/Server/Diagnostics/GumpProfile.cs
Normal file
47
Projects/Server/Diagnostics/GumpProfile.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class GumpProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<Type, GumpProfile> _profiles = new Dictionary<Type, GumpProfile>();
|
||||
|
||||
public GumpProfile(Type type) : base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<GumpProfile> Profiles => _profiles.Values;
|
||||
|
||||
public static GumpProfile Acquire(Type type)
|
||||
{
|
||||
if (!Core.Profiling)
|
||||
return null;
|
||||
|
||||
if (!_profiles.TryGetValue(type, out GumpProfile prof))
|
||||
_profiles.Add(type, prof = new GumpProfile(type));
|
||||
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
108
Projects/Server/Diagnostics/PacketProfile.cs
Normal file
108
Projects/Server/Diagnostics/PacketProfile.cs
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public abstract class BasePacketProfile : BaseProfile
|
||||
{
|
||||
protected BasePacketProfile(string name) : base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public long TotalLength{ get; private set; }
|
||||
|
||||
public double AverageLength => (double)TotalLength / Math.Max(1, Count);
|
||||
|
||||
public void Finish(long 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 Dictionary<Type, PacketSendProfile> _profiles = new Dictionary<Type, PacketSendProfile>();
|
||||
|
||||
private long _created;
|
||||
|
||||
public PacketSendProfile(Type type) : base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<PacketSendProfile> Profiles => _profiles.Values;
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketSendProfile Acquire(Type type)
|
||||
{
|
||||
if (!_profiles.TryGetValue(type, out PacketSendProfile prof))
|
||||
_profiles.Add(type, prof = new PacketSendProfile(type));
|
||||
|
||||
return prof;
|
||||
}
|
||||
|
||||
public void Increment()
|
||||
{
|
||||
Interlocked.Increment(ref _created);
|
||||
}
|
||||
|
||||
public override void WriteTo(TextWriter op)
|
||||
{
|
||||
base.WriteTo(op);
|
||||
|
||||
op.Write("\t{0,12:N0}", _created);
|
||||
}
|
||||
}
|
||||
|
||||
public class PacketReceiveProfile : BasePacketProfile
|
||||
{
|
||||
private static Dictionary<int, PacketReceiveProfile> _profiles = new Dictionary<int, PacketReceiveProfile>();
|
||||
|
||||
public PacketReceiveProfile(int packetId)
|
||||
: base($"0x{packetId:X2}")
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<PacketReceiveProfile> Profiles => _profiles.Values;
|
||||
|
||||
[MethodImpl(MethodImplOptions.Synchronized)]
|
||||
public static PacketReceiveProfile Acquire(int packetId)
|
||||
{
|
||||
if (!_profiles.TryGetValue(packetId, out PacketReceiveProfile prof))
|
||||
_profiles.Add(packetId, prof = new PacketReceiveProfile(packetId));
|
||||
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Projects/Server/Diagnostics/TargetProfile.cs
Normal file
48
Projects/Server/Diagnostics/TargetProfile.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class TargetProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<Type, TargetProfile> _profiles = new Dictionary<Type, TargetProfile>();
|
||||
|
||||
public TargetProfile(Type type)
|
||||
: base(type.FullName)
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<TargetProfile> Profiles => _profiles.Values;
|
||||
|
||||
public static TargetProfile Acquire(Type type)
|
||||
{
|
||||
if (!Core.Profiling)
|
||||
return null;
|
||||
|
||||
if (!_profiles.TryGetValue(type, out TargetProfile prof))
|
||||
_profiles.Add(type, prof = new TargetProfile(type));
|
||||
|
||||
return prof;
|
||||
}
|
||||
}
|
||||
}
|
||||
61
Projects/Server/Diagnostics/TimerProfile.cs
Normal file
61
Projects/Server/Diagnostics/TimerProfile.cs
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/***************************************************************************
|
||||
* PacketProfile.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.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server.Diagnostics
|
||||
{
|
||||
public class TimerProfile : BaseProfile
|
||||
{
|
||||
private static Dictionary<string, TimerProfile> _profiles = new Dictionary<string, TimerProfile>();
|
||||
|
||||
public TimerProfile(string name)
|
||||
: base(name)
|
||||
{
|
||||
}
|
||||
|
||||
public static IEnumerable<TimerProfile> Profiles => _profiles.Values;
|
||||
|
||||
public long Created{ get; set; }
|
||||
|
||||
public long Started{ get; set; }
|
||||
|
||||
public long Stopped{ get; set; }
|
||||
|
||||
public static TimerProfile Acquire(string name)
|
||||
{
|
||||
if (!Core.Profiling)
|
||||
return null;
|
||||
|
||||
if (!_profiles.TryGetValue(name, out TimerProfile prof))
|
||||
_profiles.Add(name, prof = new TimerProfile(name));
|
||||
|
||||
return prof;
|
||||
}
|
||||
|
||||
public override void WriteTo(TextWriter op)
|
||||
{
|
||||
base.WriteTo(op);
|
||||
|
||||
op.Write("\t{0,12:N0} {1,12:N0} {2,-12:N0}", Created, Started, Stopped);
|
||||
}
|
||||
}
|
||||
}
|
||||
411
Projects/Server/Effects.cs
Normal file
411
Projects/Server/Effects.cs
Normal file
|
|
@ -0,0 +1,411 @@
|
|||
/***************************************************************************
|
||||
* Effects.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 Server.Network;
|
||||
|
||||
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
|
||||
{
|
||||
public static ParticleSupportType ParticleSupportType{ get; set; } = ParticleSupportType.Detect;
|
||||
|
||||
public static bool SendParticlesTo(NetState state)
|
||||
{
|
||||
return ParticleSupportType == ParticleSupportType.Full ||
|
||||
ParticleSupportType == ParticleSupportType.Detect && state.IsUOTDClient;
|
||||
}
|
||||
|
||||
public static void PlaySound(IPoint3D p, Map map, int soundID)
|
||||
{
|
||||
if (soundID <= -1)
|
||||
return;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(new Point3D(p));
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (playSound == null)
|
||||
playSound = Packet.Acquire(new PlaySound(soundID, p));
|
||||
|
||||
state.Send(playSound);
|
||||
}
|
||||
|
||||
Packet.Release(playSound);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e)
|
||||
{
|
||||
SendBoltEffect(e, true, 0);
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e, bool sound)
|
||||
{
|
||||
SendBoltEffect(e, sound, 0);
|
||||
}
|
||||
|
||||
public static void SendBoltEffect(IEntity e, bool sound, int hue)
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
e.ProcessDelta();
|
||||
|
||||
Packet preEffect = null, boltEffect = null, playSound = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
if (state.Mobile.CanSee(e))
|
||||
{
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (preEffect == null)
|
||||
preEffect = Packet.Acquire(new TargetParticleEffect(e, 0, 10, 5, 0, 0, 5031, 3, 0));
|
||||
|
||||
state.Send(preEffect);
|
||||
}
|
||||
|
||||
if (boltEffect == null)
|
||||
boltEffect = Packet.Acquire(new BoltEffect(e, hue));
|
||||
|
||||
state.Send(boltEffect);
|
||||
|
||||
if (sound)
|
||||
{
|
||||
if (playSound == null)
|
||||
playSound = Packet.Acquire(new PlaySound(0x29, e));
|
||||
|
||||
state.Send(playSound);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(preEffect);
|
||||
Packet.Release(boltEffect);
|
||||
Packet.Release(playSound);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, 10, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, speed, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendLocationEffect(p, map, itemID, duration, 10, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendLocationEffect(IPoint3D p, Map map, int itemID, int duration, int speed, int hue,
|
||||
int renderMode)
|
||||
{
|
||||
SendPacket(p, map, new LocationEffect(p, itemID, speed, duration, hue, renderMode));
|
||||
}
|
||||
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect)
|
||||
{
|
||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, 0);
|
||||
}
|
||||
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int effect, int unknown)
|
||||
{
|
||||
SendLocationParticles(e, itemID, speed, duration, 0, 0, effect, unknown);
|
||||
}
|
||||
|
||||
public static void SendLocationParticles(IEntity e, int itemID, int speed, int duration, int hue, int renderMode,
|
||||
int effect, int unknown)
|
||||
{
|
||||
Map map = e.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(e.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new LocationParticleEffect(e, itemID, speed, duration, hue,
|
||||
renderMode, effect, unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID != 0)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new LocationEffect(e, itemID, speed, duration, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( e.Location, e.Map, new LocationParticleEffect( e, itemID, speed, duration, hue, renderMode, effect, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int duration)
|
||||
{
|
||||
SendTargetEffect(target, itemID, duration, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration)
|
||||
{
|
||||
SendTargetEffect(target, itemID, speed, duration, 0, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int duration, int hue, int renderMode)
|
||||
{
|
||||
SendTargetEffect(target, itemID, 10, duration, hue, renderMode);
|
||||
}
|
||||
|
||||
public static void SendTargetEffect(IEntity target, int itemID, int speed, int duration, int hue, int renderMode)
|
||||
{
|
||||
if (target is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
SendPacket(target.Location, target.Map, new TargetEffect(target, itemID, speed, duration, hue, renderMode));
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int effect,
|
||||
EffectLayer layer)
|
||||
{
|
||||
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, 0);
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int effect,
|
||||
EffectLayer layer, int unknown)
|
||||
{
|
||||
SendTargetParticles(target, itemID, speed, duration, 0, 0, effect, layer, unknown);
|
||||
}
|
||||
|
||||
public static void SendTargetParticles(IEntity target, int itemID, int speed, int duration, int hue, int renderMode,
|
||||
int effect, EffectLayer layer, int unknown)
|
||||
{
|
||||
if (target is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
Map map = target.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(target.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new TargetParticleEffect(target, itemID, speed, duration, hue,
|
||||
renderMode, effect, (int)layer, unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID != 0)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new TargetEffect(target, itemID, speed, duration, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( target.Location, target.Map, new TargetParticleEffect( target, itemID, speed, duration, hue, renderMode, effect, (int)layer, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendMovingEffect(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue = 0, int renderMode = 0)
|
||||
{
|
||||
if (from is Mobile mobile)
|
||||
mobile.ProcessDelta();
|
||||
|
||||
if (to is Mobile mobile1)
|
||||
mobile1.ProcessDelta();
|
||||
|
||||
SendPacket(from.Location, from.Map,
|
||||
new MovingEffect(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode));
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect,
|
||||
explodeSound, 0);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int effect, int explodeEffect, int explodeSound, int unknown)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, 0, 0, effect, explodeEffect,
|
||||
explodeSound, unknown);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||
int unknown)
|
||||
{
|
||||
SendMovingParticles(from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect,
|
||||
explodeEffect, explodeSound, (EffectLayer)255, unknown);
|
||||
}
|
||||
|
||||
public static void SendMovingParticles(IEntity from, IEntity to, int itemID, int speed, int duration,
|
||||
bool fixedDirection, bool explodes, int hue, int renderMode, int effect, int explodeEffect, int explodeSound,
|
||||
EffectLayer layer, int unknown)
|
||||
{
|
||||
if (from is Mobile fromMob)
|
||||
fromMob.ProcessDelta();
|
||||
|
||||
if (to is Mobile toMob)
|
||||
toMob.ProcessDelta();
|
||||
|
||||
Map map = from.Map;
|
||||
|
||||
if (map != null)
|
||||
{
|
||||
Packet particles = null, regular = null;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(from.Location);
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
|
||||
if (SendParticlesTo(state))
|
||||
{
|
||||
if (particles == null)
|
||||
particles = Packet.Acquire(new MovingParticleEffect(from, to, itemID, speed, duration,
|
||||
fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, layer,
|
||||
unknown));
|
||||
|
||||
state.Send(particles);
|
||||
}
|
||||
else if (itemID > 1)
|
||||
{
|
||||
if (regular == null)
|
||||
regular = Packet.Acquire(new MovingEffect(from, to, itemID, speed, duration, fixedDirection,
|
||||
explodes, hue, renderMode));
|
||||
|
||||
state.Send(regular);
|
||||
}
|
||||
}
|
||||
|
||||
Packet.Release(particles);
|
||||
Packet.Release(regular);
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
//SendPacket( from.Location, from.Map, new MovingParticleEffect( from, to, itemID, speed, duration, fixedDirection, explodes, hue, renderMode, effect, explodeEffect, explodeSound, unknown ) );
|
||||
}
|
||||
|
||||
public static void SendPacket(Point3D origin, Map map, Packet p)
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(origin);
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
|
||||
public static void SendPacket(IPoint3D origin, Map map, Packet p)
|
||||
{
|
||||
if (map == null)
|
||||
return;
|
||||
|
||||
IPooledEnumerable<NetState> eable = map.GetClientsInRange(new Point3D(origin));
|
||||
|
||||
p.Acquire();
|
||||
|
||||
foreach (NetState state in eable)
|
||||
{
|
||||
state.Mobile.ProcessDelta();
|
||||
state.Send(p);
|
||||
}
|
||||
|
||||
p.Release();
|
||||
|
||||
eable.Free();
|
||||
}
|
||||
}
|
||||
}
|
||||
1132
Projects/Server/EventSink.cs
Normal file
1132
Projects/Server/EventSink.cs
Normal file
File diff suppressed because it is too large
Load diff
346
Projects/Server/ExpansionInfo.cs
Normal file
346
Projects/Server/ExpansionInfo.cs
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/***************************************************************************
|
||||
* ExpansionInfo.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
|
||||
{
|
||||
public enum Expansion
|
||||
{
|
||||
None,
|
||||
T2A,
|
||||
UOR,
|
||||
UOTD,
|
||||
LBR,
|
||||
AOS,
|
||||
SE,
|
||||
ML,
|
||||
SA,
|
||||
HS,
|
||||
TOL
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum ClientFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Felucca = 0x00000001,
|
||||
Trammel = 0x00000002,
|
||||
Ilshenar = 0x00000004,
|
||||
Malas = 0x00000008,
|
||||
Tokuno = 0x00000010,
|
||||
TerMur = 0x00000020,
|
||||
Unk1 = 0x00000040,
|
||||
Unk2 = 0x00000080,
|
||||
UOTD = 0x00000100
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum FeatureFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
T2A = 0x00000001,
|
||||
UOR = 0x00000002,
|
||||
UOTD = 0x00000004,
|
||||
LBR = 0x00000008,
|
||||
AOS = 0x00000010,
|
||||
SixthCharacterSlot = 0x00000020,
|
||||
SE = 0x00000040,
|
||||
ML = 0x00000080,
|
||||
EigthAge = 0x00000100,
|
||||
NinthAge = 0x00000200, /* Crystal/Shadow Custom House Tiles */
|
||||
TenthAge = 0x00000400,
|
||||
IncreasedStorage = 0x00000800, /* Increased Housing/Bank Storage */
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
RoleplayFaces = 0x00002000,
|
||||
TrialAccount = 0x00004000,
|
||||
LiveAccount = 0x00008000,
|
||||
SA = 0x00010000,
|
||||
HS = 0x00020000,
|
||||
Gothic = 0x00040000,
|
||||
Rustic = 0x00080000,
|
||||
Jungle = 0x00100000,
|
||||
Shadowguard = 0x00200000,
|
||||
TOL = 0x00400000,
|
||||
|
||||
ExpansionNone = None,
|
||||
ExpansionT2A = T2A,
|
||||
ExpansionUOR = ExpansionT2A | UOR,
|
||||
ExpansionUOTD = ExpansionUOR | UOTD,
|
||||
ExpansionLBR = ExpansionUOTD | LBR,
|
||||
ExpansionAOS = ExpansionLBR | AOS | LiveAccount,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML | NinthAge,
|
||||
ExpansionSA = ExpansionML | SA | Gothic | Rustic,
|
||||
ExpansionHS = ExpansionSA | HS,
|
||||
ExpansionTOL = ExpansionHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum CharacterListFlags
|
||||
{
|
||||
None = 0x00000000,
|
||||
Unk1 = 0x00000001,
|
||||
OverwriteConfigButton = 0x00000002,
|
||||
OneCharacterSlot = 0x00000004,
|
||||
ContextMenus = 0x00000008,
|
||||
SlotLimit = 0x00000010,
|
||||
AOS = 0x00000020,
|
||||
SixthCharacterSlot = 0x00000040,
|
||||
SE = 0x00000080,
|
||||
ML = 0x00000100,
|
||||
Unk2 = 0x00000200,
|
||||
UO3DClientType = 0x00000400,
|
||||
Unk3 = 0x00000800,
|
||||
SeventhCharacterSlot = 0x00001000,
|
||||
Unk4 = 0x00002000,
|
||||
NewMovementSystem = 0x00004000,
|
||||
NewFeluccaAreas = 0x00008000,
|
||||
|
||||
ExpansionNone = ContextMenus, //
|
||||
ExpansionT2A = ContextMenus, //
|
||||
ExpansionUOR = ContextMenus, // None
|
||||
ExpansionUOTD = ContextMenus, //
|
||||
ExpansionLBR = ContextMenus, //
|
||||
ExpansionAOS = ContextMenus | AOS,
|
||||
ExpansionSE = ExpansionAOS | SE,
|
||||
ExpansionML = ExpansionSE | ML,
|
||||
ExpansionSA = ExpansionML,
|
||||
ExpansionHS = ExpansionSA,
|
||||
ExpansionTOL = ExpansionHS
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum HousingFlags
|
||||
{
|
||||
None = 0x0,
|
||||
AOS = 0x10,
|
||||
SE = 0x40,
|
||||
ML = 0x80,
|
||||
Crystal = 0x200,
|
||||
SA = 0x10000,
|
||||
HS = 0x20000,
|
||||
Gothic = 0x40000,
|
||||
Rustic = 0x80000,
|
||||
Jungle = 0x100000,
|
||||
Shadowguard = 0x200000,
|
||||
TOL = 0x400000,
|
||||
|
||||
HousingAOS = AOS,
|
||||
HousingSE = HousingAOS | SE,
|
||||
HousingML = HousingSE | ML | Crystal,
|
||||
HousingSA = HousingML | SA | Gothic | Rustic,
|
||||
HousingHS = HousingSA | HS,
|
||||
HousingTOL = HousingHS | TOL | Jungle | Shadowguard
|
||||
}
|
||||
|
||||
public class ExpansionInfo
|
||||
{
|
||||
static ExpansionInfo()
|
||||
{
|
||||
Table = new[]
|
||||
{
|
||||
new ExpansionInfo(
|
||||
0,
|
||||
"None",
|
||||
ClientFlags.None,
|
||||
FeatureFlags.ExpansionNone,
|
||||
CharacterListFlags.ExpansionNone,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
1,
|
||||
"The Second Age",
|
||||
ClientFlags.Felucca,
|
||||
FeatureFlags.ExpansionT2A,
|
||||
CharacterListFlags.ExpansionT2A,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
2,
|
||||
"Renaissance",
|
||||
ClientFlags.Trammel,
|
||||
FeatureFlags.ExpansionUOR,
|
||||
CharacterListFlags.ExpansionUOR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
3,
|
||||
"Third Dawn",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionUOTD,
|
||||
CharacterListFlags.ExpansionUOTD,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
4,
|
||||
"Blackthorn's Revenge",
|
||||
ClientFlags.Ilshenar,
|
||||
FeatureFlags.ExpansionLBR,
|
||||
CharacterListFlags.ExpansionLBR,
|
||||
HousingFlags.None),
|
||||
new ExpansionInfo(
|
||||
5,
|
||||
"Age of Shadows",
|
||||
ClientFlags.Malas,
|
||||
FeatureFlags.ExpansionAOS,
|
||||
CharacterListFlags.ExpansionAOS,
|
||||
HousingFlags.HousingAOS),
|
||||
new ExpansionInfo(
|
||||
6,
|
||||
"Samurai Empire",
|
||||
ClientFlags.Tokuno,
|
||||
FeatureFlags.ExpansionSE,
|
||||
CharacterListFlags.ExpansionSE,
|
||||
HousingFlags.HousingSE),
|
||||
new ExpansionInfo(
|
||||
7,
|
||||
"Mondain's Legacy",
|
||||
new ClientVersion("5.0.0a"),
|
||||
FeatureFlags.ExpansionML,
|
||||
CharacterListFlags.ExpansionML,
|
||||
HousingFlags.HousingML),
|
||||
new ExpansionInfo(
|
||||
8,
|
||||
"Stygian Abyss",
|
||||
ClientFlags.TerMur,
|
||||
FeatureFlags.ExpansionSA,
|
||||
CharacterListFlags.ExpansionSA,
|
||||
HousingFlags.HousingSA),
|
||||
new ExpansionInfo(
|
||||
9,
|
||||
"High Seas",
|
||||
new ClientVersion("7.0.9.0"),
|
||||
FeatureFlags.ExpansionHS,
|
||||
CharacterListFlags.ExpansionHS,
|
||||
HousingFlags.HousingHS),
|
||||
new ExpansionInfo(
|
||||
10,
|
||||
"Time of Legends",
|
||||
new ClientVersion("7.0.45.65"),
|
||||
FeatureFlags.ExpansionTOL,
|
||||
CharacterListFlags.ExpansionTOL,
|
||||
HousingFlags.HousingTOL)
|
||||
};
|
||||
}
|
||||
|
||||
public 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 static ExpansionInfo CoreExpansion => GetInfo(Core.Expansion);
|
||||
|
||||
public static ExpansionInfo[] Table{ get; }
|
||||
|
||||
public int ID{ get; }
|
||||
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 static FeatureFlags GetFeatures(Expansion ex)
|
||||
{
|
||||
ExpansionInfo 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;
|
||||
}
|
||||
|
||||
return FeatureFlags.ExpansionNone;
|
||||
}
|
||||
|
||||
public static ExpansionInfo GetInfo(Expansion ex)
|
||||
{
|
||||
return GetInfo((int)ex);
|
||||
}
|
||||
|
||||
public static ExpansionInfo GetInfo(int ex)
|
||||
{
|
||||
int v = ex;
|
||||
|
||||
if (v < 0 || v >= Table.Length) v = 0;
|
||||
|
||||
return Table[v];
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return Name;
|
||||
}
|
||||
}
|
||||
}
|
||||
479
Projects/Server/Geometry.cs
Normal file
479
Projects/Server/Geometry.cs
Normal file
|
|
@ -0,0 +1,479 @@
|
|||
/***************************************************************************
|
||||
* Geometry.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
|
||||
{
|
||||
[Parsable]
|
||||
public struct Point2D : IPoint2D, 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 => m_X;
|
||||
set => m_X = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => m_Y = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({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 override bool Equals(object o)
|
||||
{
|
||||
return o is IPoint2D p && m_X == p.X && m_Y == p.Y;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return m_X ^ 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, Point2D r)
|
||||
{
|
||||
return l.m_X != r.m_X || l.m_Y != r.m_Y;
|
||||
}
|
||||
|
||||
public static bool operator ==(Point2D l, IPoint2D r)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y;
|
||||
}
|
||||
|
||||
public static bool operator !=(Point2D l, IPoint2D r)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && (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)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && 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)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && 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)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && 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)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && l.m_X <= r.X && l.m_Y <= r.Y;
|
||||
}
|
||||
}
|
||||
|
||||
[Parsable]
|
||||
public struct Point3D : IPoint3D, 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 => m_X;
|
||||
set => m_X = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => m_Y = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Z
|
||||
{
|
||||
get => m_Z;
|
||||
set => m_Z = value;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"({m_X}, {m_Y}, {m_Z})";
|
||||
}
|
||||
|
||||
public override bool Equals(object o)
|
||||
{
|
||||
return o is IPoint3D p && m_X == p.X && m_Y == p.Y && m_Z == p.Z;
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
return m_X ^ m_Y ^ m_Z;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && l.m_X == r.X && l.m_Y == r.Y && l.m_Z == r.Z;
|
||||
}
|
||||
|
||||
public static bool operator !=(Point3D l, IPoint3D r)
|
||||
{
|
||||
return !ReferenceEquals(r, null) && (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;
|
||||
}
|
||||
}
|
||||
|
||||
[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 => m_Start;
|
||||
set => m_Start = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point2D End
|
||||
{
|
||||
get => m_End;
|
||||
set => m_End = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int X
|
||||
{
|
||||
get => m_Start.m_X;
|
||||
set => m_Start.m_X = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Y
|
||||
{
|
||||
get => m_Start.m_Y;
|
||||
set => m_Start.m_Y = value;
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Width
|
||||
{
|
||||
get => 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 => 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 $"({X}, {Y})+({Width}, {Height})";
|
||||
}
|
||||
}
|
||||
|
||||
[NoSort]
|
||||
[PropertyObject]
|
||||
public struct Rectangle3D
|
||||
{
|
||||
public Rectangle3D(Point3D start, Point3D end)
|
||||
{
|
||||
Start = start;
|
||||
End = end;
|
||||
}
|
||||
|
||||
public Rectangle3D(int x, int y, int z, int width, int height, int depth)
|
||||
{
|
||||
Start = new Point3D(x, y, z);
|
||||
End = new Point3D(x + width, y + height, z + depth);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point3D Start{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public Point3D End{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Width => End.X - Start.X;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Height => End.Y - Start.Y;
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public int Depth => End.Z - Start.Z;
|
||||
|
||||
public bool Contains(Point3D p)
|
||||
{
|
||||
return p.m_X >= Start.m_X
|
||||
&& p.m_X < End.m_X
|
||||
&& p.m_Y >= Start.m_Y
|
||||
&& p.m_Y < End.m_Y
|
||||
&& p.m_Z >= Start.m_Z
|
||||
&& p.m_Z < End.m_Z;
|
||||
}
|
||||
|
||||
public bool Contains(IPoint3D p)
|
||||
{
|
||||
return p.X >= Start.m_X
|
||||
&& p.X < End.m_X
|
||||
&& p.Y >= Start.m_Y
|
||||
&& p.Y < End.m_Y
|
||||
&& p.Z >= Start.m_Z
|
||||
&& p.Z < End.m_Z;
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Projects/Server/Guild.cs
Normal file
121
Projects/Server/Guild.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/***************************************************************************
|
||||
* Guild.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.Collections.Generic;
|
||||
|
||||
namespace Server.Guilds
|
||||
{
|
||||
public enum GuildType
|
||||
{
|
||||
Regular,
|
||||
Chaos,
|
||||
Order
|
||||
}
|
||||
|
||||
public abstract class BaseGuild : ISerializable
|
||||
{
|
||||
private static uint m_NextID = 1;
|
||||
|
||||
protected BaseGuild(uint Id) //serialization ctor
|
||||
{
|
||||
this.Id = Id;
|
||||
List.Add(this.Id, this);
|
||||
if (this.Id + 1 > m_NextID)
|
||||
m_NextID = this.Id + 1;
|
||||
}
|
||||
|
||||
protected BaseGuild()
|
||||
{
|
||||
Id = m_NextID++;
|
||||
List.Add(Id, this);
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Counselor)]
|
||||
public uint Id{ get; }
|
||||
|
||||
public abstract string Abbreviation{ get; set; }
|
||||
public abstract string Name{ get; set; }
|
||||
public abstract GuildType Type{ get; set; }
|
||||
public abstract bool Disbanded{ get; }
|
||||
|
||||
public static Dictionary<uint, BaseGuild> List{ get; } = new Dictionary<uint, BaseGuild>();
|
||||
|
||||
int ISerializable.TypeReference => 0;
|
||||
|
||||
uint ISerializable.SerialIdentity => Id;
|
||||
public abstract void Serialize(GenericWriter writer);
|
||||
|
||||
public abstract void Deserialize(GenericReader reader);
|
||||
public abstract void OnDelete(Mobile mob);
|
||||
|
||||
public static BaseGuild Find(uint id)
|
||||
{
|
||||
List.TryGetValue(id, out BaseGuild g);
|
||||
|
||||
return g;
|
||||
}
|
||||
|
||||
public static BaseGuild FindByName(string name)
|
||||
{
|
||||
foreach (BaseGuild g in List.Values)
|
||||
if (g.Name == name)
|
||||
return g;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static BaseGuild FindByAbbrev(string abbr)
|
||||
{
|
||||
foreach (BaseGuild g in List.Values)
|
||||
if (g.Abbreviation == abbr)
|
||||
return g;
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static List<BaseGuild> Search(string find)
|
||||
{
|
||||
string[] words = find.ToLower().Split(' ');
|
||||
List<BaseGuild> results = new List<BaseGuild>();
|
||||
|
||||
foreach (BaseGuild g in List.Values)
|
||||
{
|
||||
bool match = true;
|
||||
string name = g.Name.ToLower();
|
||||
for (int i = 0; i < words.Length; i++)
|
||||
if (name.IndexOf(words[i]) == -1)
|
||||
{
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
|
||||
if (match)
|
||||
results.Add(g);
|
||||
}
|
||||
|
||||
return results;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"0x{Id:X} \"{Name} [{Abbreviation}]\"";
|
||||
}
|
||||
}
|
||||
}
|
||||
373
Projects/Server/Gumps/Gump.cs
Normal file
373
Projects/Server/Gumps/Gump.cs
Normal file
|
|
@ -0,0 +1,373 @@
|
|||
/***************************************************************************
|
||||
* Gump.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class Gump
|
||||
{
|
||||
private static uint m_NextSerial = 1;
|
||||
|
||||
private static byte[] m_BeginLayout = StringToBuffer("{ ");
|
||||
private static byte[] m_EndLayout = StringToBuffer(" }");
|
||||
|
||||
private static byte[] m_NoMove = StringToBuffer("{ nomove }");
|
||||
private static byte[] m_NoClose = StringToBuffer("{ noclose }");
|
||||
private static byte[] m_NoDispose = StringToBuffer("{ nodispose }");
|
||||
private static byte[] m_NoResize = StringToBuffer("{ noresize }");
|
||||
private bool m_Closable = true;
|
||||
private bool m_Disposable = true;
|
||||
|
||||
private bool m_Draggable = true;
|
||||
private bool m_Resizable = true;
|
||||
|
||||
private uint m_Serial;
|
||||
private List<string> m_Strings;
|
||||
|
||||
internal int m_TextEntries, m_Switches;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public Gump(int x, int y)
|
||||
{
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
} while (m_Serial == 0); // standard client apparently doesn't send a gump response packet if serial == 0
|
||||
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
|
||||
TypeID = GetTypeID(GetType());
|
||||
|
||||
Entries = new List<GumpEntry>();
|
||||
m_Strings = new List<string>();
|
||||
}
|
||||
|
||||
public int TypeID{ get; }
|
||||
|
||||
public List<GumpEntry> Entries{ get; }
|
||||
|
||||
public uint Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set
|
||||
{
|
||||
if (m_Serial != value)
|
||||
{
|
||||
m_Serial = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set
|
||||
{
|
||||
if (m_X != value)
|
||||
{
|
||||
m_X = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set
|
||||
{
|
||||
if (m_Y != value)
|
||||
{
|
||||
m_Y = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Disposable
|
||||
{
|
||||
get => m_Disposable;
|
||||
set
|
||||
{
|
||||
if (m_Disposable != value)
|
||||
{
|
||||
m_Disposable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Resizable
|
||||
{
|
||||
get => m_Resizable;
|
||||
set
|
||||
{
|
||||
if (m_Resizable != value)
|
||||
{
|
||||
m_Resizable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Draggable
|
||||
{
|
||||
get => m_Draggable;
|
||||
set
|
||||
{
|
||||
if (m_Draggable != value)
|
||||
{
|
||||
m_Draggable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Closable
|
||||
{
|
||||
get => m_Closable;
|
||||
set
|
||||
{
|
||||
if (m_Closable != value)
|
||||
{
|
||||
m_Closable = value;
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTypeID(Type type)
|
||||
{
|
||||
return type?.FullName?.GetHashCode() ?? -1;
|
||||
}
|
||||
|
||||
public void Invalidate()
|
||||
{
|
||||
//if ( m_Strings.Count > 0 )
|
||||
// m_Strings.Clear();
|
||||
}
|
||||
|
||||
public void AddPage(int page)
|
||||
{
|
||||
Add(new GumpPage(page));
|
||||
}
|
||||
|
||||
public void AddAlphaRegion(int x, int y, int width, int height)
|
||||
{
|
||||
Add(new GumpAlphaRegion(x, y, width, height));
|
||||
}
|
||||
|
||||
public void AddBackground(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
Add(new GumpBackground(x, y, width, height, gumpID));
|
||||
}
|
||||
|
||||
public void AddButton(int x, int y, int normalID, int pressedID, int buttonID,
|
||||
GumpButtonType type = GumpButtonType.Reply, int param = 0)
|
||||
{
|
||||
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 = false, bool scrollbar = false)
|
||||
{
|
||||
Add(new GumpHtml(x, y, width, height, text, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddHtmlLocalized(int x, int y, int width, int height, int number, bool background = false, bool scrollbar = false)
|
||||
{
|
||||
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 = false,
|
||||
bool scrollbar = false)
|
||||
{
|
||||
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 = false, bool scrollbar = false)
|
||||
{
|
||||
Add(new GumpHtmlLocalized(x, y, width, height, number, args, color, background, scrollbar));
|
||||
}
|
||||
|
||||
public void AddImage(int x, int y, int gumpID, int hue = 0)
|
||||
{
|
||||
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, int localizedTooltip = -1)
|
||||
{
|
||||
Add(new GumpImageTileButton(x, y, normalID, pressedID, buttonID, type, param, itemID, hue, width, height,
|
||||
localizedTooltip));
|
||||
}
|
||||
|
||||
public void AddItem(int x, int y, int itemID, int hue = 0)
|
||||
{
|
||||
Add(new GumpItem(x, y, itemID, hue));
|
||||
}
|
||||
|
||||
public void AddLabel(int x, int y, int hue, string text)
|
||||
{
|
||||
Add(new GumpLabel(x, y, hue, text));
|
||||
}
|
||||
|
||||
public void AddLabelCropped(int x, int y, int width, int height, int hue, string text)
|
||||
{
|
||||
Add(new GumpLabelCropped(x, y, width, height, hue, text));
|
||||
}
|
||||
|
||||
public void AddRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
Add(new GumpRadio(x, y, inactiveID, activeID, initialState, switchID));
|
||||
}
|
||||
|
||||
public void AddTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText, int size = 0)
|
||||
{
|
||||
Add(new GumpTextEntryLimited(x, y, width, height, hue, entryID, initialText, size));
|
||||
}
|
||||
|
||||
public void AddItemProperty(uint serial)
|
||||
{
|
||||
Add(new GumpItemProperty(serial));
|
||||
}
|
||||
|
||||
public void Add(GumpEntry g)
|
||||
{
|
||||
if (g.Parent != this)
|
||||
{
|
||||
g.Parent = this;
|
||||
}
|
||||
else if (!Entries.Contains(g))
|
||||
{
|
||||
Invalidate();
|
||||
Entries.Add(g);
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(GumpEntry g)
|
||||
{
|
||||
if (g == null || !Entries.Contains(g))
|
||||
return;
|
||||
|
||||
Invalidate();
|
||||
Entries.Remove(g);
|
||||
g.Parent = null;
|
||||
}
|
||||
|
||||
public int Intern(string value)
|
||||
{
|
||||
int indexOf = m_Strings.IndexOf(value);
|
||||
|
||||
if (indexOf >= 0) return indexOf;
|
||||
|
||||
Invalidate();
|
||||
m_Strings.Add(value);
|
||||
return m_Strings.Count - 1;
|
||||
}
|
||||
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.AddGump(this);
|
||||
state.Send(Compile(state));
|
||||
}
|
||||
|
||||
public static byte[] StringToBuffer(string str)
|
||||
{
|
||||
return Encoding.ASCII.GetBytes(str);
|
||||
}
|
||||
|
||||
private Packet Compile(NetState ns = null)
|
||||
{
|
||||
IGumpWriter disp;
|
||||
|
||||
if (ns?.Unpack == true)
|
||||
disp = new DisplayGumpPacked(this);
|
||||
else
|
||||
disp = new DisplayGumpFast(this);
|
||||
|
||||
if (!m_Draggable)
|
||||
disp.AppendLayout(m_NoMove);
|
||||
|
||||
if (!m_Closable)
|
||||
disp.AppendLayout(m_NoClose);
|
||||
|
||||
if (!m_Disposable)
|
||||
disp.AppendLayout(m_NoDispose);
|
||||
|
||||
if (!m_Resizable)
|
||||
disp.AppendLayout(m_NoResize);
|
||||
|
||||
int count = Entries.Count;
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
GumpEntry e = Entries[i];
|
||||
|
||||
disp.AppendLayout(m_BeginLayout);
|
||||
e.AppendTo(ns, disp);
|
||||
disp.AppendLayout(m_EndLayout);
|
||||
}
|
||||
|
||||
disp.WriteStrings(m_Strings);
|
||||
|
||||
disp.Flush();
|
||||
|
||||
m_TextEntries = disp.TextEntries;
|
||||
m_Switches = disp.Switches;
|
||||
|
||||
return (Packet)disp;
|
||||
}
|
||||
|
||||
public virtual void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
}
|
||||
|
||||
public virtual void OnServerClose(NetState owner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Projects/Server/Gumps/GumpAlphaRegion.cs
Normal file
77
Projects/Server/Gumps/GumpAlphaRegion.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpAlphaRegion : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("checkertrans");
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpAlphaRegion(int x, int y, int width, int height)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ checkertrans {m_X} {m_Y} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Projects/Server/Gumps/GumpBackground.cs
Normal file
86
Projects/Server/Gumps/GumpBackground.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpBackground : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("resizepic");
|
||||
private int m_GumpID;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpBackground(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ resizepic {m_X} {m_Y} {m_GumpID} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
}
|
||||
}
|
||||
}
|
||||
121
Projects/Server/Gumps/GumpButton.cs
Normal file
121
Projects/Server/Gumps/GumpButton.cs
Normal file
|
|
@ -0,0 +1,121 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public enum GumpButtonType
|
||||
{
|
||||
Page = 0,
|
||||
Reply = 1
|
||||
}
|
||||
|
||||
public class GumpButton : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("button");
|
||||
private int m_ButtonID;
|
||||
private int m_ID1, m_ID2;
|
||||
private int m_Param;
|
||||
private GumpButtonType m_Type;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpButton(int x, int y, int normalID, int pressedID, int buttonID,
|
||||
GumpButtonType type = GumpButtonType.Reply, int param = 0)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = normalID;
|
||||
m_ID2 = pressedID;
|
||||
m_ButtonID = buttonID;
|
||||
m_Type = type;
|
||||
m_Param = param;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta(ref m_ButtonID, value);
|
||||
}
|
||||
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
Gump parent = Parent;
|
||||
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta(ref m_Param, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ button {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout((int)m_Type);
|
||||
disp.AppendLayout(m_Param);
|
||||
disp.AppendLayout(m_ButtonID);
|
||||
}
|
||||
}
|
||||
}
|
||||
97
Projects/Server/Gumps/GumpCheck.cs
Normal file
97
Projects/Server/Gumps/GumpCheck.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpCheck : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("checkbox");
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpCheck(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta(ref m_InitialState, value);
|
||||
}
|
||||
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta(ref m_SwitchID, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ checkbox {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout(m_InitialState);
|
||||
disp.AppendLayout(m_SwitchID);
|
||||
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Projects/Server/Gumps/GumpEntry.cs
Normal file
78
Projects/Server/Gumps/GumpEntry.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/***************************************************************************
|
||||
* GumpEntry.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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public abstract class GumpEntry
|
||||
{
|
||||
private Gump m_Parent;
|
||||
|
||||
public Gump Parent
|
||||
{
|
||||
get => m_Parent;
|
||||
set
|
||||
{
|
||||
if (m_Parent != value)
|
||||
{
|
||||
m_Parent?.Remove(this);
|
||||
|
||||
m_Parent = value;
|
||||
|
||||
m_Parent?.Add(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void Delta(ref uint var, uint val)
|
||||
{
|
||||
if (var != val)
|
||||
var = val;
|
||||
}
|
||||
|
||||
protected void Delta(ref int var, int val)
|
||||
{
|
||||
if (var != val)
|
||||
var = val;
|
||||
}
|
||||
|
||||
protected void Delta(ref bool var, bool val)
|
||||
{
|
||||
if (var != val)
|
||||
var = val;
|
||||
}
|
||||
|
||||
protected void Delta(ref string var, string val)
|
||||
{
|
||||
if (var != val)
|
||||
var = val;
|
||||
}
|
||||
|
||||
protected void Delta(ref object[] var, object[] val)
|
||||
{
|
||||
if (var != val)
|
||||
var = val;
|
||||
}
|
||||
|
||||
public abstract string Compile(NetState ns);
|
||||
public abstract void AppendTo(NetState ns, IGumpWriter disp);
|
||||
}
|
||||
}
|
||||
52
Projects/Server/Gumps/GumpGroup.cs
Normal file
52
Projects/Server/Gumps/GumpGroup.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpGroup : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("group");
|
||||
private int m_Group;
|
||||
|
||||
public GumpGroup(int group)
|
||||
{
|
||||
m_Group = group;
|
||||
}
|
||||
|
||||
public int Group
|
||||
{
|
||||
get => m_Group;
|
||||
set => Delta(ref m_Group, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ group {m_Group} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Group);
|
||||
}
|
||||
}
|
||||
}
|
||||
104
Projects/Server/Gumps/GumpHtml.cs
Normal file
104
Projects/Server/Gumps/GumpHtml.cs
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpHtml : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("htmlgump");
|
||||
private bool m_Background, m_Scrollbar;
|
||||
private string m_Text;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpHtml(int x, int y, int width, int height, string text, bool background, bool scrollbar)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Text = text;
|
||||
m_Background = background;
|
||||
m_Scrollbar = scrollbar;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta(ref m_Background, value);
|
||||
}
|
||||
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta(ref m_Scrollbar, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ htmlgump {m_X} {m_Y} {m_Width} {m_Height} {Parent.Intern(m_Text)} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
}
|
||||
}
|
||||
}
|
||||
233
Projects/Server/Gumps/GumpHtmlLocalized.cs
Normal file
233
Projects/Server/Gumps/GumpHtmlLocalized.cs
Normal file
|
|
@ -0,0 +1,233 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public enum GumpHtmlLocalizedType
|
||||
{
|
||||
Plain,
|
||||
Color,
|
||||
Args
|
||||
}
|
||||
|
||||
public class GumpHtmlLocalized : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutNamePlain = Gump.StringToBuffer("xmfhtmlgump");
|
||||
private static byte[] m_LayoutNameColor = Gump.StringToBuffer("xmfhtmlgumpcolor");
|
||||
private static byte[] m_LayoutNameArgs = Gump.StringToBuffer("xmfhtmltok");
|
||||
private string m_Args;
|
||||
private bool m_Background, m_Scrollbar;
|
||||
private int m_Color;
|
||||
private int m_Number;
|
||||
|
||||
private GumpHtmlLocalizedType m_Type;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpHtmlLocalized(int x, int y, int width, int height, int number,
|
||||
bool background = false, bool scrollbar = false)
|
||||
{
|
||||
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 = false, bool scrollbar = false)
|
||||
{
|
||||
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 = false, bool scrollbar = false)
|
||||
{
|
||||
// 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 int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta(ref m_Number, value);
|
||||
}
|
||||
|
||||
public string Args
|
||||
{
|
||||
get => m_Args;
|
||||
set => Delta(ref m_Args, value);
|
||||
}
|
||||
|
||||
public int Color
|
||||
{
|
||||
get => m_Color;
|
||||
set => Delta(ref m_Color, value);
|
||||
}
|
||||
|
||||
public bool Background
|
||||
{
|
||||
get => m_Background;
|
||||
set => Delta(ref m_Background, value);
|
||||
}
|
||||
|
||||
public bool Scrollbar
|
||||
{
|
||||
get => m_Scrollbar;
|
||||
set => Delta(ref m_Scrollbar, value);
|
||||
}
|
||||
|
||||
public GumpHtmlLocalizedType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
Parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
switch (m_Type)
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
return
|
||||
$"{{ xmfhtmlgump {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} }}";
|
||||
|
||||
case GumpHtmlLocalizedType.Color:
|
||||
return
|
||||
$"{{ xmfhtmlgumpcolor {m_X} {m_Y} {m_Width} {m_Height} {m_Number} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} }}";
|
||||
|
||||
default: // GumpHtmlLocalizedType.Args
|
||||
return
|
||||
$"{{ xmfhtmltok {m_X} {m_Y} {m_Width} {m_Height} {(m_Background ? 1 : 0)} {(m_Scrollbar ? 1 : 0)} {m_Color} {m_Number} @{m_Args}@ }}";
|
||||
}
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
switch (m_Type)
|
||||
{
|
||||
case GumpHtmlLocalizedType.Plain:
|
||||
{
|
||||
disp.AppendLayout(m_LayoutNamePlain);
|
||||
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Number);
|
||||
disp.AppendLayout(m_Background);
|
||||
disp.AppendLayout(m_Scrollbar);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
85
Projects/Server/Gumps/GumpImage.cs
Normal file
85
Projects/Server/Gumps/GumpImage.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImage : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppic");
|
||||
private static byte[] m_HueEquals = Gump.StringToBuffer(" hue=");
|
||||
private int m_GumpID;
|
||||
private int m_Hue;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpImage(int x, int y, int gumpID, int hue = 0)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_GumpID = gumpID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return m_Hue == 0 ? $"{{ gumppic {m_X} {m_Y} {m_GumpID} }}" :
|
||||
$"{{ gumppic {m_X} {m_Y} {m_GumpID} hue={m_Hue} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
|
||||
if (m_Hue != 0)
|
||||
{
|
||||
disp.AppendLayout(m_HueEquals);
|
||||
disp.AppendLayoutNS(m_Hue);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
172
Projects/Server/Gumps/GumpImageTileButton.cs
Normal file
172
Projects/Server/Gumps/GumpImageTileButton.cs
Normal file
|
|
@ -0,0 +1,172 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImageTileButton : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("buttontileart");
|
||||
private static byte[] m_LayoutTooltip = Gump.StringToBuffer(" }{ tooltip");
|
||||
private int m_ButtonID;
|
||||
private int m_Height;
|
||||
private int m_Hue;
|
||||
private int m_ID1, m_ID2;
|
||||
|
||||
private int m_ItemID;
|
||||
private int m_Param;
|
||||
private GumpButtonType m_Type;
|
||||
|
||||
private int m_Width;
|
||||
|
||||
//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;
|
||||
|
||||
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 = -1)
|
||||
{
|
||||
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;
|
||||
|
||||
LocalizedTooltip = localizedTooltip;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int NormalID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public int PressedID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public int ButtonID
|
||||
{
|
||||
get => m_ButtonID;
|
||||
set => Delta(ref m_ButtonID, value);
|
||||
}
|
||||
|
||||
public GumpButtonType Type
|
||||
{
|
||||
get => m_Type;
|
||||
set
|
||||
{
|
||||
if (m_Type != value)
|
||||
{
|
||||
m_Type = value;
|
||||
|
||||
Gump parent = Parent;
|
||||
|
||||
parent?.Invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int Param
|
||||
{
|
||||
get => m_Param;
|
||||
set => Delta(ref m_Param, value);
|
||||
}
|
||||
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta(ref m_ItemID, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int LocalizedTooltip{ get; set; }
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
if (LocalizedTooltip > 0)
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}{{ tooltip {LocalizedTooltip} }}";
|
||||
return
|
||||
$"{{ buttontileart {m_X} {m_Y} {m_ID1} {m_ID2} {(int)m_Type} {m_Param} {m_ButtonID} {m_ItemID} {m_Hue} {m_Width} {m_Height} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout((int)m_Type);
|
||||
disp.AppendLayout(m_Param);
|
||||
disp.AppendLayout(m_ButtonID);
|
||||
|
||||
disp.AppendLayout(m_ItemID);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
|
||||
if (LocalizedTooltip > 0)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutTooltip);
|
||||
disp.AppendLayout(LocalizedTooltip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
86
Projects/Server/Gumps/GumpImageTiled.cs
Normal file
86
Projects/Server/Gumps/GumpImageTiled.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpImageTiled : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("gumppictiled");
|
||||
private int m_GumpID;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpImageTiled(int x, int y, int width, int height, int gumpID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_GumpID = gumpID;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int GumpID
|
||||
{
|
||||
get => m_GumpID;
|
||||
set => Delta(ref m_GumpID, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ gumppictiled {m_X} {m_Y} {m_Width} {m_Height} {m_GumpID} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_GumpID);
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Projects/Server/Gumps/GumpItem.cs
Normal file
82
Projects/Server/Gumps/GumpItem.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpItem : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("tilepic");
|
||||
private static byte[] m_LayoutNameHue = Gump.StringToBuffer("tilepichue");
|
||||
private int m_Hue;
|
||||
private int m_ItemID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpItem(int x, int y, int itemID, int hue = 0)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ItemID = itemID;
|
||||
m_Hue = hue;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int ItemID
|
||||
{
|
||||
get => m_ItemID;
|
||||
set => Delta(ref m_ItemID, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return m_Hue == 0 ? $"{{ tilepic {m_X} {m_Y} {m_ItemID} }}" :
|
||||
$"{{ tilepichue {m_X} {m_Y} {m_ItemID} {m_Hue} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_Hue == 0 ? m_LayoutName : m_LayoutNameHue);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ItemID);
|
||||
|
||||
if (m_Hue != 0)
|
||||
disp.AppendLayout(m_Hue);
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Projects/Server/Gumps/GumpItemProperty.cs
Normal file
52
Projects/Server/Gumps/GumpItemProperty.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpItemProperty : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("itemproperty");
|
||||
private uint m_Serial;
|
||||
|
||||
public GumpItemProperty(uint serial)
|
||||
{
|
||||
m_Serial = serial;
|
||||
}
|
||||
|
||||
public uint Serial
|
||||
{
|
||||
get => m_Serial;
|
||||
set => Delta(ref m_Serial, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ itemproperty {m_Serial} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Serial);
|
||||
}
|
||||
}
|
||||
}
|
||||
78
Projects/Server/Gumps/GumpLabel.cs
Normal file
78
Projects/Server/Gumps/GumpLabel.cs
Normal file
|
|
@ -0,0 +1,78 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpLabel : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("text");
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpLabel(int x, int y, int hue, string text)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ text {m_X} {m_Y} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
95
Projects/Server/Gumps/GumpLabelCropped.cs
Normal file
95
Projects/Server/Gumps/GumpLabelCropped.cs
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpLabelCropped : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("croppedtext");
|
||||
private int m_Hue;
|
||||
private string m_Text;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpLabelCropped(int x, int y, int width, int height, int hue, string text)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_Text = text;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public string Text
|
||||
{
|
||||
get => m_Text;
|
||||
set => Delta(ref m_Text, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ croppedtext {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {Parent.Intern(m_Text)} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(Parent.Intern(m_Text));
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Projects/Server/Gumps/GumpPage.cs
Normal file
52
Projects/Server/Gumps/GumpPage.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpPage : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("page");
|
||||
private int m_Page;
|
||||
|
||||
public GumpPage(int page)
|
||||
{
|
||||
m_Page = page;
|
||||
}
|
||||
|
||||
public int Page
|
||||
{
|
||||
get => m_Page;
|
||||
set => Delta(ref m_Page, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ page {m_Page} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Page);
|
||||
}
|
||||
}
|
||||
}
|
||||
97
Projects/Server/Gumps/GumpRadio.cs
Normal file
97
Projects/Server/Gumps/GumpRadio.cs
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpRadio : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("radio");
|
||||
private int m_ID1, m_ID2;
|
||||
private bool m_InitialState;
|
||||
private int m_SwitchID;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpRadio(int x, int y, int inactiveID, int activeID, bool initialState, int switchID)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_ID1 = inactiveID;
|
||||
m_ID2 = activeID;
|
||||
m_InitialState = initialState;
|
||||
m_SwitchID = switchID;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int InactiveID
|
||||
{
|
||||
get => m_ID1;
|
||||
set => Delta(ref m_ID1, value);
|
||||
}
|
||||
|
||||
public int ActiveID
|
||||
{
|
||||
get => m_ID2;
|
||||
set => Delta(ref m_ID2, value);
|
||||
}
|
||||
|
||||
public bool InitialState
|
||||
{
|
||||
get => m_InitialState;
|
||||
set => Delta(ref m_InitialState, value);
|
||||
}
|
||||
|
||||
public int SwitchID
|
||||
{
|
||||
get => m_SwitchID;
|
||||
set => Delta(ref m_SwitchID, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ radio {m_X} {m_Y} {m_ID1} {m_ID2} {(m_InitialState ? 1 : 0)} {m_SwitchID} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_ID1);
|
||||
disp.AppendLayout(m_ID2);
|
||||
disp.AppendLayout(m_InitialState);
|
||||
disp.AppendLayout(m_SwitchID);
|
||||
|
||||
disp.Switches++;
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Projects/Server/Gumps/GumpTextEntry.cs
Normal file
107
Projects/Server/Gumps/GumpTextEntry.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTextEntry : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("textentry");
|
||||
private int m_EntryID;
|
||||
private int m_Hue;
|
||||
private string m_InitialText;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpTextEntry(int x, int y, int width, int height, int hue, int entryID, string initialText)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public int EntryID
|
||||
{
|
||||
get => m_EntryID;
|
||||
set => Delta(ref m_EntryID, value);
|
||||
}
|
||||
|
||||
public string InitialText
|
||||
{
|
||||
get => m_InitialText;
|
||||
set => Delta(ref m_InitialText, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ textentry {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_EntryID);
|
||||
disp.AppendLayout(Parent.Intern(m_InitialText));
|
||||
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
116
Projects/Server/Gumps/GumpTextEntryLimited.cs
Normal file
116
Projects/Server/Gumps/GumpTextEntryLimited.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTextEntryLimited : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("textentrylimited");
|
||||
private int m_EntryID;
|
||||
private int m_Hue;
|
||||
private string m_InitialText;
|
||||
private int m_Size;
|
||||
private int m_Width, m_Height;
|
||||
private int m_X, m_Y;
|
||||
|
||||
public GumpTextEntryLimited(int x, int y, int width, int height, int hue, int entryID, string initialText, int size = 0)
|
||||
{
|
||||
m_X = x;
|
||||
m_Y = y;
|
||||
m_Width = width;
|
||||
m_Height = height;
|
||||
m_Hue = hue;
|
||||
m_EntryID = entryID;
|
||||
m_InitialText = initialText;
|
||||
m_Size = size;
|
||||
}
|
||||
|
||||
public int X
|
||||
{
|
||||
get => m_X;
|
||||
set => Delta(ref m_X, value);
|
||||
}
|
||||
|
||||
public int Y
|
||||
{
|
||||
get => m_Y;
|
||||
set => Delta(ref m_Y, value);
|
||||
}
|
||||
|
||||
public int Width
|
||||
{
|
||||
get => m_Width;
|
||||
set => Delta(ref m_Width, value);
|
||||
}
|
||||
|
||||
public int Height
|
||||
{
|
||||
get => m_Height;
|
||||
set => Delta(ref m_Height, value);
|
||||
}
|
||||
|
||||
public int Hue
|
||||
{
|
||||
get => m_Hue;
|
||||
set => Delta(ref m_Hue, value);
|
||||
}
|
||||
|
||||
public int EntryID
|
||||
{
|
||||
get => m_EntryID;
|
||||
set => Delta(ref m_EntryID, value);
|
||||
}
|
||||
|
||||
public string InitialText
|
||||
{
|
||||
get => m_InitialText;
|
||||
set => Delta(ref m_InitialText, value);
|
||||
}
|
||||
|
||||
public int Size
|
||||
{
|
||||
get => m_Size;
|
||||
set => Delta(ref m_Size, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return
|
||||
$"{{ textentrylimited {m_X} {m_Y} {m_Width} {m_Height} {m_Hue} {m_EntryID} {Parent.Intern(m_InitialText)} {m_Size} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_X);
|
||||
disp.AppendLayout(m_Y);
|
||||
disp.AppendLayout(m_Width);
|
||||
disp.AppendLayout(m_Height);
|
||||
disp.AppendLayout(m_Hue);
|
||||
disp.AppendLayout(m_EntryID);
|
||||
disp.AppendLayout(Parent.Intern(m_InitialText));
|
||||
disp.AppendLayout(m_Size);
|
||||
|
||||
disp.TextEntries++;
|
||||
}
|
||||
}
|
||||
}
|
||||
52
Projects/Server/Gumps/GumpTooltip.cs
Normal file
52
Projects/Server/Gumps/GumpTooltip.cs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
/***************************************************************************
|
||||
* 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 Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GumpTooltip : GumpEntry
|
||||
{
|
||||
private static byte[] m_LayoutName = Gump.StringToBuffer("tooltip");
|
||||
private int m_Number;
|
||||
|
||||
public GumpTooltip(int number)
|
||||
{
|
||||
m_Number = number;
|
||||
}
|
||||
|
||||
public int Number
|
||||
{
|
||||
get => m_Number;
|
||||
set => Delta(ref m_Number, value);
|
||||
}
|
||||
|
||||
public override string Compile(NetState ns)
|
||||
{
|
||||
return $"{{ tooltip {m_Number} }}";
|
||||
}
|
||||
|
||||
public override void AppendTo(NetState ns, IGumpWriter disp)
|
||||
{
|
||||
disp.AppendLayout(m_LayoutName);
|
||||
disp.AppendLayout(m_Number);
|
||||
}
|
||||
}
|
||||
}
|
||||
69
Projects/Server/Gumps/RelayInfo.cs
Normal file
69
Projects/Server/Gumps/RelayInfo.cs
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/***************************************************************************
|
||||
* 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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class TextRelay
|
||||
{
|
||||
public TextRelay(int entryID, string text)
|
||||
{
|
||||
EntryID = entryID;
|
||||
Text = text;
|
||||
}
|
||||
|
||||
public int EntryID{ get; }
|
||||
|
||||
public string Text{ get; }
|
||||
}
|
||||
|
||||
public class RelayInfo
|
||||
{
|
||||
public RelayInfo(int buttonID, int[] switches, TextRelay[] textEntries)
|
||||
{
|
||||
ButtonID = buttonID;
|
||||
Switches = switches;
|
||||
TextEntries = textEntries;
|
||||
}
|
||||
|
||||
public int ButtonID{ get; }
|
||||
|
||||
public int[] Switches{ get; }
|
||||
|
||||
public TextRelay[] TextEntries{ get; }
|
||||
|
||||
public bool IsSwitched(int switchID)
|
||||
{
|
||||
for (int i = 0; i < Switches.Length; ++i)
|
||||
if (Switches[i] == switchID)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public TextRelay GetTextEntry(int entryID)
|
||||
{
|
||||
for (int i = 0; i < TextEntries.Length; ++i)
|
||||
if (TextEntries[i].EntryID == entryID)
|
||||
return TextEntries[i];
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Projects/Server/HuePicker.cs
Normal file
53
Projects/Server/HuePicker.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
/***************************************************************************
|
||||
* HuePicker.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 Server.Network;
|
||||
|
||||
namespace Server.HuePickers
|
||||
{
|
||||
public class HuePicker
|
||||
{
|
||||
private static int m_NextSerial = 1;
|
||||
|
||||
public HuePicker(int itemID)
|
||||
{
|
||||
do
|
||||
{
|
||||
Serial = m_NextSerial++;
|
||||
} while (Serial == 0);
|
||||
|
||||
ItemID = itemID;
|
||||
}
|
||||
|
||||
public int Serial{ get; }
|
||||
|
||||
public int ItemID{ get; }
|
||||
|
||||
public virtual void OnResponse(int hue)
|
||||
{
|
||||
}
|
||||
|
||||
public void SendTo(NetState state)
|
||||
{
|
||||
state.Send(new DisplayHuePicker(this));
|
||||
state.AddHuePicker(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Projects/Server/IAccount.cs
Normal file
126
Projects/Server/IAccount.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
/***************************************************************************
|
||||
* IAccount.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.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 interface IGoldAccount
|
||||
{
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Gold owned by the player.
|
||||
/// The value does not include the value of Platinum and ranges from
|
||||
/// 0 to 999,999,999 by default.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalGold{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// This amount represents the current amount of Platinum owned by the player.
|
||||
/// The value does not include the value of Gold and ranges from
|
||||
/// 0 to 2,147,483,647 by default.
|
||||
/// One Platinum represents the value of CurrencyThreshold in Gold.
|
||||
/// </summary>
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
int TotalPlat{ get; }
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Gold into this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be deposited to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositGold(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to deposit the given amount of Platinum into this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to deposit.</param>
|
||||
/// <returns>True if successful, false if amount given is less than or equal to zero.</returns>
|
||||
bool DepositPlat(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Gold from this account.
|
||||
/// If the given amount is greater than the CurrencyThreshold,
|
||||
/// Platinum will be withdrawn to offset the difference.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawGold(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to withdraw the given amount of Platinum from this account.
|
||||
/// </summary>
|
||||
/// <param name="amount">Amount to withdraw.</param>
|
||||
/// <returns>True if successful, false if balance was too low.</returns>
|
||||
bool WithdrawPlat(int amount);
|
||||
|
||||
/// <summary>
|
||||
/// Returns total gold inclusive of platinum, capped to Int32.
|
||||
/// This is strictly for backwards compatibility
|
||||
/// </summary>
|
||||
/// <returns>Total gold, capped at Int32.MaxValue</returns>
|
||||
long GetTotalGold();
|
||||
}
|
||||
|
||||
public interface IAccount : IGoldAccount, IComparable<IAccount>
|
||||
{
|
||||
string Username{ get; set; }
|
||||
string Email{ get; set; }
|
||||
AccessLevel AccessLevel{ get; set; }
|
||||
|
||||
int Length{ get; }
|
||||
int Limit{ get; }
|
||||
int Count{ get; }
|
||||
Mobile this[int index]{ get; set; }
|
||||
|
||||
void Delete();
|
||||
void SetPassword(string password);
|
||||
bool CheckPassword(string password);
|
||||
}
|
||||
}
|
||||
85
Projects/Server/IEntity.cs
Normal file
85
Projects/Server/IEntity.cs
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
/***************************************************************************
|
||||
* IEntity.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
|
||||
{
|
||||
public interface IEntity : IPoint3D, IComparable<IEntity>
|
||||
{
|
||||
Serial Serial{ get; }
|
||||
Point3D Location{ get; }
|
||||
Map Map{ get; }
|
||||
bool Deleted{ get; }
|
||||
void MoveToWorld(Point3D location, Map map);
|
||||
|
||||
void Delete();
|
||||
void ProcessDelta();
|
||||
}
|
||||
|
||||
public class Entity : IEntity, IComparable<Entity>
|
||||
{
|
||||
public Entity(Serial serial, Point3D loc, Map map)
|
||||
{
|
||||
Serial = serial;
|
||||
Location = loc;
|
||||
Map = map;
|
||||
Deleted = false;
|
||||
}
|
||||
|
||||
public int CompareTo(Entity other)
|
||||
{
|
||||
return CompareTo((IEntity)other);
|
||||
}
|
||||
|
||||
public int CompareTo(IEntity other)
|
||||
{
|
||||
return other == null ? -1 : Serial.CompareTo(other.Serial);
|
||||
}
|
||||
|
||||
public Serial Serial{ get; }
|
||||
|
||||
public Point3D Location{ get; private set; }
|
||||
|
||||
public int X => Location.X;
|
||||
|
||||
public int Y => Location.Y;
|
||||
|
||||
public int Z => Location.Z;
|
||||
|
||||
public Map Map{ get; private set; }
|
||||
|
||||
public virtual void MoveToWorld(Point3D newLocation, Map map)
|
||||
{
|
||||
Location = newLocation;
|
||||
Map = map;
|
||||
}
|
||||
|
||||
public bool Deleted{ get; }
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
}
|
||||
|
||||
public void ProcessDelta()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Projects/Server/Insensitive.cs
Normal file
72
Projects/Server/Insensitive.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
/***************************************************************************
|
||||
* Insensitive.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Insensitive
|
||||
{
|
||||
public static IComparer<string> Comparer{ get; } = StringComparer.OrdinalIgnoreCase;
|
||||
|
||||
public static int Compare(string a, string b)
|
||||
{
|
||||
return Comparer.Compare(a, b);
|
||||
}
|
||||
|
||||
public static bool Equals(string a, string b)
|
||||
{
|
||||
if (a == null && b == null)
|
||||
return true;
|
||||
if (a == null || b == null || a.Length != b.Length)
|
||||
return false;
|
||||
|
||||
return Comparer.Compare(a, b) == 0;
|
||||
}
|
||||
|
||||
public static bool StartsWith(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
return Comparer.Compare(a.Substring(0, b.Length), b) == 0;
|
||||
}
|
||||
|
||||
public static bool EndsWith(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
return Comparer.Compare(a.Substring(a.Length - b.Length), b) == 0;
|
||||
}
|
||||
|
||||
public static bool Contains(string a, string b)
|
||||
{
|
||||
if (a == null || b == null || a.Length < b.Length)
|
||||
return false;
|
||||
|
||||
a = a.ToLower();
|
||||
b = b.ToLower();
|
||||
|
||||
return a.IndexOf(b) >= 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
115
Projects/Server/Interfaces.cs
Normal file
115
Projects/Server/Interfaces.cs
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
/***************************************************************************
|
||||
* Interfaces.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Server.Mobiles;
|
||||
|
||||
namespace Server.Mobiles
|
||||
{
|
||||
public interface IMount
|
||||
{
|
||||
Mobile Rider{ get; set; }
|
||||
void OnRiderDamaged(int amount, Mobile from, bool willKill);
|
||||
}
|
||||
|
||||
public interface IMountItem
|
||||
{
|
||||
IMount Mount{ get; }
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IVendor
|
||||
{
|
||||
DateTime LastRestock{ get; set; }
|
||||
TimeSpan RestockDelay{ get; }
|
||||
bool OnBuyItems(Mobile from, List<BuyItemResponse> list);
|
||||
bool OnSellItems(Mobile from, List<SellItemResponse> list);
|
||||
void Restock();
|
||||
}
|
||||
|
||||
public interface IPoint2D
|
||||
{
|
||||
int X{ get; }
|
||||
int Y{ get; }
|
||||
}
|
||||
|
||||
public interface IPoint3D : IPoint2D
|
||||
{
|
||||
int Z{ get; }
|
||||
}
|
||||
|
||||
public interface ICarvable
|
||||
{
|
||||
void Carve(Mobile from, Item item);
|
||||
}
|
||||
|
||||
public interface IWeapon
|
||||
{
|
||||
int MaxRange{ get; }
|
||||
void OnBeforeSwing(Mobile attacker, Mobile defender);
|
||||
TimeSpan OnSwing(Mobile attacker, Mobile defender);
|
||||
void GetStatusDamage(Mobile from, out int min, out int max);
|
||||
}
|
||||
|
||||
public interface IHued
|
||||
{
|
||||
int HuedItemID{ get; }
|
||||
}
|
||||
|
||||
public interface ISpell
|
||||
{
|
||||
bool IsCasting{ get; }
|
||||
void OnCasterHurt();
|
||||
void OnCasterKilled();
|
||||
void OnConnectionChanged();
|
||||
bool OnCasterMoving(Direction d);
|
||||
bool OnCasterEquipping(Item item);
|
||||
bool OnCasterUsingObject(IEntity entity);
|
||||
bool OnCastInTown(Region r);
|
||||
void FinishSequence();
|
||||
}
|
||||
|
||||
public interface IParty
|
||||
{
|
||||
void OnStamChanged(Mobile m);
|
||||
void OnManaChanged(Mobile m);
|
||||
void OnStatsQuery(Mobile beholder, Mobile beheld);
|
||||
}
|
||||
|
||||
public interface ISpawner
|
||||
{
|
||||
bool UnlinkOnTaming{ get; }
|
||||
Point3D HomeLocation{ get; }
|
||||
int HomeRange{ get; }
|
||||
Region Region{ get; }
|
||||
|
||||
void Remove(ISpawnable spawn);
|
||||
}
|
||||
|
||||
public interface ISpawnable : IEntity
|
||||
{
|
||||
ISpawner Spawner{ get; set; }
|
||||
void OnBeforeSpawn(Point3D location, Map map);
|
||||
void OnAfterSpawn();
|
||||
}
|
||||
}
|
||||
3877
Projects/Server/Item.cs
Normal file
3877
Projects/Server/Item.cs
Normal file
File diff suppressed because it is too large
Load diff
58
Projects/Server/ItemBounds.cs
Normal file
58
Projects/Server/ItemBounds.cs
Normal file
|
|
@ -0,0 +1,58 @@
|
|||
/***************************************************************************
|
||||
* ItemBounds.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class ItemBounds
|
||||
{
|
||||
static ItemBounds()
|
||||
{
|
||||
Table = new Rectangle2D[TileData.ItemTable.Length];
|
||||
|
||||
if (File.Exists("Data/Binary/Bounds.bin"))
|
||||
using (FileStream fs = new FileStream("Data/Binary/Bounds.bin", FileMode.Open, FileAccess.Read,
|
||||
FileShare.Read))
|
||||
{
|
||||
BinaryReader bin = new BinaryReader(fs);
|
||||
|
||||
int count = Math.Min(Table.Length, (int)(fs.Length / 8));
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
{
|
||||
int xMin = bin.ReadInt16();
|
||||
int yMin = bin.ReadInt16();
|
||||
int xMax = bin.ReadInt16();
|
||||
int yMax = bin.ReadInt16();
|
||||
|
||||
Table[i].Set(xMin, yMin, xMax - xMin + 1, yMax - yMin + 1);
|
||||
}
|
||||
|
||||
bin.Close();
|
||||
}
|
||||
else
|
||||
Console.WriteLine("Warning: Data/Binary/Bounds.bin does not exist");
|
||||
}
|
||||
|
||||
public static Rectangle2D[] Table{ get; }
|
||||
}
|
||||
}
|
||||
164
Projects/Server/Items/BaseMulti.cs
Normal file
164
Projects/Server/Items/BaseMulti.cs
Normal file
|
|
@ -0,0 +1,164 @@
|
|||
/***************************************************************************
|
||||
* BaseMulti.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.Items
|
||||
{
|
||||
public abstract class BaseMulti : Item
|
||||
{
|
||||
public BaseMulti(int itemID) : base(itemID)
|
||||
{
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public BaseMulti(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public override int ItemID
|
||||
{
|
||||
get => base.ItemID;
|
||||
set
|
||||
{
|
||||
if (base.ItemID != value)
|
||||
{
|
||||
Map facet = Parent == null ? Map : null;
|
||||
|
||||
facet?.OnLeave(this);
|
||||
|
||||
base.ItemID = value;
|
||||
|
||||
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;
|
||||
return 1078872 + id;
|
||||
}
|
||||
|
||||
return base.LabelNumber;
|
||||
}
|
||||
}
|
||||
|
||||
public virtual bool AllowsRelativeDrop => false;
|
||||
|
||||
public virtual MultiComponentList Components => MultiData.GetComponents(ItemID);
|
||||
|
||||
[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 GetMaxUpdateRange()
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
|
||||
public override int GetUpdateRange(Mobile m)
|
||||
{
|
||||
return 22;
|
||||
}
|
||||
|
||||
public virtual bool Contains(Point2D p)
|
||||
{
|
||||
return Contains(p.m_X, p.m_Y);
|
||||
}
|
||||
|
||||
public virtual bool Contains(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);
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool Contains(Item item)
|
||||
{
|
||||
if (item.Map == Map)
|
||||
return Contains(item.X, item.Y);
|
||||
return false;
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
1743
Projects/Server/Items/Container.cs
Normal file
1743
Projects/Server/Items/Container.cs
Normal file
File diff suppressed because it is too large
Load diff
141
Projects/Server/Items/Containers.cs
Normal file
141
Projects/Server/Items/Containers.cs
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
/***************************************************************************
|
||||
* Containers.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 Server.Accounting;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class BankBox : Container
|
||||
{
|
||||
public BankBox(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public BankBox(Mobile owner) : base(0xE7C)
|
||||
{
|
||||
Layer = Layer.Bank;
|
||||
Movable = false;
|
||||
Owner = owner;
|
||||
}
|
||||
|
||||
public override int DefaultMaxWeight => 0;
|
||||
|
||||
public override bool IsVirtualItem => true;
|
||||
|
||||
public Mobile Owner{ get; private set; }
|
||||
|
||||
public bool Opened{ get; private set; }
|
||||
|
||||
public static bool SendDeleteOnClose{ get; set; }
|
||||
|
||||
public void Open()
|
||||
{
|
||||
Opened = true;
|
||||
|
||||
if (Owner != null)
|
||||
{
|
||||
Owner.PrivateOverheadMessage(MessageType.Regular, 0x3B2, true,
|
||||
$"Bank container has {TotalItems} items, {TotalWeight} stones", Owner.NetState);
|
||||
Owner.Send(new EquipUpdate(this));
|
||||
DisplayTo(Owner);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
|
||||
writer.Write(Owner);
|
||||
writer.Write(Opened);
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
Owner = reader.ReadMobile();
|
||||
Opened = reader.ReadBool();
|
||||
|
||||
if (Owner == null)
|
||||
Delete();
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ItemID == 0xE41)
|
||||
ItemID = 0xE7C;
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
Opened = false;
|
||||
|
||||
if (SendDeleteOnClose)
|
||||
Owner?.Send(RemovePacket);
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnDoubleClick(Mobile from)
|
||||
{
|
||||
}
|
||||
|
||||
public override DeathMoveResult OnParentDeath(Mobile parent)
|
||||
{
|
||||
return DeathMoveResult.RemainEquipped;
|
||||
}
|
||||
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
return (check == Owner && Opened || check.AccessLevel >= AccessLevel.GameMaster) && base.IsAccessibleTo(check);
|
||||
}
|
||||
|
||||
public override bool OnDragDrop(Mobile from, Item dropped)
|
||||
{
|
||||
return (from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) && base.OnDragDrop(from, dropped);
|
||||
}
|
||||
|
||||
public override bool OnDragDropInto(Mobile from, Item item, Point3D p)
|
||||
{
|
||||
return (from == Owner && Opened || from.AccessLevel >= AccessLevel.GameMaster) &&
|
||||
base.OnDragDropInto(from, item, p);
|
||||
}
|
||||
|
||||
public override int GetTotal(TotalType type)
|
||||
{
|
||||
if (AccountGold.Enabled && Owner?.Account != null && type == TotalType.Gold)
|
||||
return Owner.Account.TotalGold;
|
||||
|
||||
return base.GetTotal(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
120
Projects/Server/Items/SecureTradeContainer.cs
Normal file
120
Projects/Server/Items/SecureTradeContainer.cs
Normal file
|
|
@ -0,0 +1,120 @@
|
|||
/***************************************************************************
|
||||
* SecureTradeContainer.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 Server.Accounting;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Items
|
||||
{
|
||||
public class SecureTradeContainer : Container
|
||||
{
|
||||
public SecureTradeContainer(SecureTrade trade) : base(0x1E5E)
|
||||
{
|
||||
Trade = trade;
|
||||
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public SecureTradeContainer(Serial serial) : base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public SecureTrade Trade{ get; }
|
||||
|
||||
public override bool CheckHold(Mobile m, Item item, bool message, bool checkItems, int plusItems, int plusWeight)
|
||||
{
|
||||
if (item == Trade.From.VirtualCheck || item == Trade.To.VirtualCheck) return true;
|
||||
|
||||
Mobile 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)
|
||||
{
|
||||
return IsChildOf(check) && Trade?.Valid == true && 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 (Trade == null)
|
||||
return;
|
||||
|
||||
if (Trade.From?.IsDisposed == false)
|
||||
Trade.From.Accepted = false;
|
||||
|
||||
if (Trade.To?.IsDisposed == false)
|
||||
Trade.To.Accepted = false;
|
||||
|
||||
Trade.Update();
|
||||
}
|
||||
|
||||
public override bool IsChildVisibleTo(Mobile m, Item child)
|
||||
{
|
||||
return child is VirtualCheck
|
||||
? AccountGold.Enabled && m.NetState?.NewSecureTrading != true
|
||||
: base.IsChildVisibleTo(m, child);
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
base.Serialize(writer);
|
||||
|
||||
writer.Write(0); // version
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
base.Deserialize(reader);
|
||||
|
||||
int version = reader.ReadInt();
|
||||
}
|
||||
}
|
||||
}
|
||||
353
Projects/Server/Items/VirtualCheck.cs
Normal file
353
Projects/Server/Items/VirtualCheck.cs
Normal file
|
|
@ -0,0 +1,353 @@
|
|||
using Server.Gumps;
|
||||
using Server.Items;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class VirtualCheck : Item
|
||||
{
|
||||
public static bool UseEditGump = false;
|
||||
|
||||
private int _Gold;
|
||||
|
||||
private int _Plat;
|
||||
|
||||
public VirtualCheck(int plat = 0, int gold = 0)
|
||||
: base(0x14F0)
|
||||
{
|
||||
Plat = plat;
|
||||
Gold = gold;
|
||||
|
||||
Movable = false;
|
||||
}
|
||||
|
||||
public VirtualCheck(Serial serial)
|
||||
: base(serial)
|
||||
{
|
||||
}
|
||||
|
||||
public override bool IsVirtualItem => true;
|
||||
|
||||
public override bool DisplayWeight => false;
|
||||
public override bool DisplayLootType => false;
|
||||
|
||||
public override double DefaultWeight => 0;
|
||||
|
||||
public override string DefaultName => "Offer Of Currency";
|
||||
|
||||
public EditGump Editor{ get; private set; }
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Plat
|
||||
{
|
||||
get => _Plat;
|
||||
set
|
||||
{
|
||||
_Plat = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.Administrator)]
|
||||
public int Gold
|
||||
{
|
||||
get => _Gold;
|
||||
set
|
||||
{
|
||||
_Gold = value;
|
||||
InvalidateProperties();
|
||||
}
|
||||
}
|
||||
|
||||
public override bool IsAccessibleTo(Mobile check)
|
||||
{
|
||||
SecureTradeContainer c = GetSecureTradeCont();
|
||||
|
||||
if (check == null || c == null) return base.IsAccessibleTo(check);
|
||||
|
||||
return c.RootParent == check && IsChildOf(c);
|
||||
}
|
||||
|
||||
public override void OnDoubleClickSecureTrade(Mobile from)
|
||||
{
|
||||
if (UseEditGump && IsAccessibleTo(from))
|
||||
{
|
||||
if (Editor?.Check?.Deleted != false)
|
||||
{
|
||||
Editor = new EditGump(from, this);
|
||||
Editor.Send();
|
||||
}
|
||||
else
|
||||
{
|
||||
Editor.Refresh(true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
|
||||
base.OnDoubleClickSecureTrade(from);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnSingleClick(Mobile from)
|
||||
{
|
||||
LabelTo(from, "Offer: {0:#,0} platinum, {1:#,0} gold", Plat, Gold);
|
||||
}
|
||||
|
||||
public override void GetProperties(ObjectPropertyList list)
|
||||
{
|
||||
base.GetProperties(list);
|
||||
|
||||
list.Add(1060738, $"{Plat:#,0} platinum, {Gold:#,0} gold"); // value: ~1_val~
|
||||
}
|
||||
|
||||
public void UpdateTrade(Mobile user)
|
||||
{
|
||||
SecureTradeContainer c = GetSecureTradeCont();
|
||||
|
||||
if (c?.Trade == null) return;
|
||||
|
||||
if (user == c.Trade.From.Mobile)
|
||||
c.Trade.UpdateFromCurrency();
|
||||
else if (user == c.Trade.To.Mobile) c.Trade.UpdateToCurrency();
|
||||
|
||||
c.ClearChecks();
|
||||
}
|
||||
|
||||
public override void OnAfterDelete()
|
||||
{
|
||||
base.OnAfterDelete();
|
||||
|
||||
if (Editor != null)
|
||||
{
|
||||
Editor.Close();
|
||||
Editor = null;
|
||||
}
|
||||
}
|
||||
|
||||
public override void Serialize(GenericWriter writer)
|
||||
{
|
||||
}
|
||||
|
||||
public override void Deserialize(GenericReader reader)
|
||||
{
|
||||
Delete();
|
||||
}
|
||||
|
||||
public class EditGump : Gump
|
||||
{
|
||||
public enum Buttons
|
||||
{
|
||||
Close,
|
||||
Clear,
|
||||
Accept,
|
||||
AllPlat,
|
||||
AllGold
|
||||
}
|
||||
|
||||
private int _Plat, _Gold;
|
||||
|
||||
public EditGump(Mobile user, VirtualCheck check)
|
||||
: base(50, 50)
|
||||
{
|
||||
User = user;
|
||||
Check = check;
|
||||
|
||||
_Plat = Check.Plat;
|
||||
_Gold = Check.Gold;
|
||||
|
||||
Closable = true;
|
||||
Disposable = true;
|
||||
Draggable = true;
|
||||
Resizable = false;
|
||||
|
||||
User.CloseGump<EditGump>();
|
||||
|
||||
CompileLayout();
|
||||
}
|
||||
|
||||
public Mobile User{ get; }
|
||||
public VirtualCheck Check{ get; private set; }
|
||||
|
||||
public override void OnServerClose(NetState owner)
|
||||
{
|
||||
base.OnServerClose(owner);
|
||||
|
||||
if (Check?.Deleted == false)
|
||||
Check.UpdateTrade(User);
|
||||
}
|
||||
|
||||
public void Close()
|
||||
{
|
||||
User.CloseGump<EditGump>();
|
||||
|
||||
if (Check?.Deleted == false)
|
||||
Check.UpdateTrade(User);
|
||||
else
|
||||
Check = null;
|
||||
}
|
||||
|
||||
public void Send()
|
||||
{
|
||||
if (Check?.Deleted == false)
|
||||
User.SendGump(this);
|
||||
else
|
||||
Close();
|
||||
}
|
||||
|
||||
public void Refresh(bool recompile)
|
||||
{
|
||||
if (Check?.Deleted != false)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
if (recompile)
|
||||
CompileLayout();
|
||||
|
||||
Close();
|
||||
Send();
|
||||
}
|
||||
|
||||
private void CompileLayout()
|
||||
{
|
||||
if (Check?.Deleted != false)
|
||||
return;
|
||||
|
||||
Entries.ForEach(e => e.Parent = null);
|
||||
Entries.Clear();
|
||||
|
||||
AddPage(0);
|
||||
|
||||
AddBackground(0, 0, 400, 160, 3500);
|
||||
|
||||
// Title
|
||||
AddImageTiled(25, 35, 350, 3, 96);
|
||||
AddImage(10, 8, 113);
|
||||
AddImage(360, 8, 113);
|
||||
|
||||
string title =
|
||||
$"<BASEFONT COLOR=#FF2F4F4F><CENTER>BANK OF {User.RawName.ToUpper()}</CENTER>";
|
||||
|
||||
AddHtml(40, 15, 320, 20, title);
|
||||
|
||||
// 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); // ->
|
||||
|
||||
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); // ->
|
||||
|
||||
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);
|
||||
AddButton(215, 128, 12003, 12004, (int)Buttons.Clear);
|
||||
AddButton(305, 128, 12000, 12002, (int)Buttons.Accept);
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState sender, RelayInfo info)
|
||||
{
|
||||
if (Check?.Deleted != false || sender.Mobile != User)
|
||||
{
|
||||
Close();
|
||||
return;
|
||||
}
|
||||
|
||||
bool refresh = false, updated = false;
|
||||
|
||||
switch ((Buttons)info.ButtonID)
|
||||
{
|
||||
case Buttons.Close:
|
||||
break;
|
||||
case Buttons.Clear:
|
||||
{
|
||||
_Plat = _Gold = 0;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.Accept:
|
||||
{
|
||||
string platText = info.GetTextEntry(0).Text;
|
||||
string goldText = info.GetTextEntry(1).Text;
|
||||
|
||||
if (!int.TryParse(platText, out _Plat))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of platinum.");
|
||||
refresh = true;
|
||||
}
|
||||
else if (!int.TryParse(goldText, out _Gold))
|
||||
{
|
||||
User.SendMessage("That is not a valid amount of gold.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
int totalPlat = User.Account.TotalPlat;
|
||||
int totalGold = User.Account.TotalGold;
|
||||
|
||||
if (totalPlat < _Plat || totalGold < _Gold)
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
_Gold = User.Account.TotalGold;
|
||||
User.SendMessage("You do not have that much currency.");
|
||||
refresh = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
Check.Plat = _Plat;
|
||||
Check.Gold = _Gold;
|
||||
updated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case Buttons.AllPlat:
|
||||
{
|
||||
_Plat = User.Account.TotalPlat;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
case Buttons.AllGold:
|
||||
{
|
||||
_Gold = User.Account.TotalGold;
|
||||
refresh = true;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
User.SendMessage("Your offer has been updated.");
|
||||
|
||||
if (refresh && Check?.Deleted == false)
|
||||
{
|
||||
Refresh(true);
|
||||
return;
|
||||
}
|
||||
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
165
Projects/Server/Items/VirtualHair.cs
Normal file
165
Projects/Server/Items/VirtualHair.cs
Normal file
|
|
@ -0,0 +1,165 @@
|
|||
/***************************************************************************
|
||||
* VirtualHair.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 Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class BaseHairInfo
|
||||
{
|
||||
protected BaseHairInfo(int itemid, int hue = 0)
|
||||
{
|
||||
ItemID = itemid;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
protected BaseHairInfo(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
switch (version)
|
||||
{
|
||||
case 0:
|
||||
{
|
||||
ItemID = reader.ReadInt();
|
||||
Hue = reader.ReadInt();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int ItemID{ get; set; }
|
||||
|
||||
[CommandProperty(AccessLevel.GameMaster)]
|
||||
public int Hue{ get; set; }
|
||||
|
||||
public virtual void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(0); //version
|
||||
writer.Write(ItemID);
|
||||
writer.Write(Hue);
|
||||
}
|
||||
}
|
||||
|
||||
public class HairInfo : BaseHairInfo
|
||||
{
|
||||
public HairInfo(int itemid)
|
||||
: base(itemid)
|
||||
{
|
||||
}
|
||||
|
||||
public HairInfo(int itemid, int hue)
|
||||
: base(itemid, hue)
|
||||
{
|
||||
}
|
||||
|
||||
public HairInfo(GenericReader reader)
|
||||
: base(reader)
|
||||
{
|
||||
}
|
||||
|
||||
// TOOD: Can we make this higher for newer clients?
|
||||
public static uint FakeSerial(Mobile parent)
|
||||
{
|
||||
return 0x7FFFFFFF - 0x400 - parent.Serial * 4;
|
||||
}
|
||||
}
|
||||
|
||||
public class FacialHairInfo : BaseHairInfo
|
||||
{
|
||||
public FacialHairInfo(int itemid)
|
||||
: base(itemid)
|
||||
{
|
||||
}
|
||||
|
||||
public FacialHairInfo(int itemid, int hue)
|
||||
: base(itemid, hue)
|
||||
{
|
||||
}
|
||||
|
||||
public FacialHairInfo(GenericReader reader)
|
||||
: base(reader)
|
||||
{
|
||||
}
|
||||
|
||||
// TOOD: Can we make this higher for newer clients?
|
||||
public static uint FakeSerial(Mobile parent)
|
||||
{
|
||||
return 0x7FFFFFFF - 0x400 - 1 - parent.Serial * 4;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class HairEquipUpdate : Packet
|
||||
{
|
||||
public HairEquipUpdate(Mobile parent)
|
||||
: base(0x2E, 15)
|
||||
{
|
||||
int hue = parent.HairHue;
|
||||
|
||||
if (parent.SolidHueOverride >= 0)
|
||||
hue = parent.SolidHueOverride;
|
||||
|
||||
m_Stream.Write(HairInfo.FakeSerial(parent));
|
||||
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;
|
||||
|
||||
m_Stream.Write(FacialHairInfo.FakeSerial(parent));
|
||||
m_Stream.Write((short)parent.FacialHairItemID);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write((byte)Layer.FacialHair);
|
||||
m_Stream.Write(parent.Serial);
|
||||
m_Stream.Write((short)hue);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RemoveHair : Packet
|
||||
{
|
||||
public RemoveHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
m_Stream.Write(HairInfo.FakeSerial(parent));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class RemoveFacialHair : Packet
|
||||
{
|
||||
public RemoveFacialHair(Mobile parent)
|
||||
: base(0x1D, 5)
|
||||
{
|
||||
m_Stream.Write(FacialHairInfo.FakeSerial(parent));
|
||||
}
|
||||
}
|
||||
}
|
||||
75
Projects/Server/KeywordList.cs
Normal file
75
Projects/Server/KeywordList.cs
Normal file
|
|
@ -0,0 +1,75 @@
|
|||
/***************************************************************************
|
||||
* KeywordList.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class KeywordList
|
||||
{
|
||||
private static int[] m_EmptyInts = new int[0];
|
||||
private int[] m_Keywords;
|
||||
|
||||
public KeywordList()
|
||||
{
|
||||
m_Keywords = new int[8];
|
||||
Count = 0;
|
||||
}
|
||||
|
||||
public int Count{ get; private set; }
|
||||
|
||||
public bool Contains(int keyword)
|
||||
{
|
||||
bool contains = false;
|
||||
|
||||
for (int i = 0; !contains && i < Count; ++i)
|
||||
contains = keyword == m_Keywords[i];
|
||||
|
||||
return contains;
|
||||
}
|
||||
|
||||
public void Add(int keyword)
|
||||
{
|
||||
if (Count + 1 > m_Keywords.Length)
|
||||
{
|
||||
int[] old = m_Keywords;
|
||||
m_Keywords = new int[old.Length * 2];
|
||||
|
||||
for (int i = 0; i < old.Length; ++i)
|
||||
m_Keywords[i] = old[i];
|
||||
}
|
||||
|
||||
m_Keywords[Count++] = keyword;
|
||||
}
|
||||
|
||||
public int[] ToArray()
|
||||
{
|
||||
if (Count == 0)
|
||||
return m_EmptyInts;
|
||||
|
||||
int[] keywords = new int[Count];
|
||||
|
||||
for (int i = 0; i < Count; ++i)
|
||||
keywords[i] = m_Keywords[i];
|
||||
|
||||
Count = 0;
|
||||
|
||||
return keywords;
|
||||
}
|
||||
}
|
||||
}
|
||||
173
Projects/Server/Layer.cs
Normal file
173
Projects/Server/Layer.cs
Normal file
|
|
@ -0,0 +1,173 @@
|
|||
namespace Server
|
||||
{
|
||||
/// <summary>
|
||||
/// Enumeration of item layer values.
|
||||
/// </summary>
|
||||
public enum Layer : byte
|
||||
{
|
||||
/// <summary>
|
||||
/// Invalid layer.
|
||||
/// </summary>
|
||||
Invalid = 0x00,
|
||||
|
||||
/// <summary>
|
||||
/// First valid layer. Equivalent to <c>Layer.OneHanded</c>.
|
||||
/// </summary>
|
||||
FirstValid = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// One handed weapon.
|
||||
/// </summary>
|
||||
OneHanded = 0x01,
|
||||
|
||||
/// <summary>
|
||||
/// Two handed weapon or shield.
|
||||
/// </summary>
|
||||
TwoHanded = 0x02,
|
||||
|
||||
/// <summary>
|
||||
/// Shoes.
|
||||
/// </summary>
|
||||
Shoes = 0x03,
|
||||
|
||||
/// <summary>
|
||||
/// Pants.
|
||||
/// </summary>
|
||||
Pants = 0x04,
|
||||
|
||||
/// <summary>
|
||||
/// Shirts.
|
||||
/// </summary>
|
||||
Shirt = 0x05,
|
||||
|
||||
/// <summary>
|
||||
/// Helmets, hats, and masks.
|
||||
/// </summary>
|
||||
Helm = 0x06,
|
||||
|
||||
/// <summary>
|
||||
/// Gloves.
|
||||
/// </summary>
|
||||
Gloves = 0x07,
|
||||
|
||||
/// <summary>
|
||||
/// Rings.
|
||||
/// </summary>
|
||||
Ring = 0x08,
|
||||
|
||||
/// <summary>
|
||||
/// Talismans.
|
||||
/// </summary>
|
||||
Talisman = 0x09,
|
||||
|
||||
/// <summary>
|
||||
/// Gorgets and necklaces.
|
||||
/// </summary>
|
||||
Neck = 0x0A,
|
||||
|
||||
/// <summary>
|
||||
/// Hair.
|
||||
/// </summary>
|
||||
Hair = 0x0B,
|
||||
|
||||
/// <summary>
|
||||
/// Half aprons.
|
||||
/// </summary>
|
||||
Waist = 0x0C,
|
||||
|
||||
/// <summary>
|
||||
/// Torso, inner layer.
|
||||
/// </summary>
|
||||
InnerTorso = 0x0D,
|
||||
|
||||
/// <summary>
|
||||
/// Bracelets.
|
||||
/// </summary>
|
||||
Bracelet = 0x0E,
|
||||
|
||||
/// <summary>
|
||||
/// Unused.
|
||||
/// </summary>
|
||||
Unused_xF = 0x0F,
|
||||
|
||||
/// <summary>
|
||||
/// Beards and mustaches.
|
||||
/// </summary>
|
||||
FacialHair = 0x10,
|
||||
|
||||
/// <summary>
|
||||
/// Torso, outer layer.
|
||||
/// </summary>
|
||||
MiddleTorso = 0x11,
|
||||
|
||||
/// <summary>
|
||||
/// Earings.
|
||||
/// </summary>
|
||||
Earrings = 0x12,
|
||||
|
||||
/// <summary>
|
||||
/// Arms and sleeves.
|
||||
/// </summary>
|
||||
Arms = 0x13,
|
||||
|
||||
/// <summary>
|
||||
/// Cloaks.
|
||||
/// </summary>
|
||||
Cloak = 0x14,
|
||||
|
||||
/// <summary>
|
||||
/// Backpacks.
|
||||
/// </summary>
|
||||
Backpack = 0x15,
|
||||
|
||||
/// <summary>
|
||||
/// Torso, outer layer.
|
||||
/// </summary>
|
||||
OuterTorso = 0x16,
|
||||
|
||||
/// <summary>
|
||||
/// Leggings, outer layer.
|
||||
/// </summary>
|
||||
OuterLegs = 0x17,
|
||||
|
||||
/// <summary>
|
||||
/// Leggings, inner layer.
|
||||
/// </summary>
|
||||
InnerLegs = 0x18,
|
||||
|
||||
/// <summary>
|
||||
/// Last valid non-internal layer. Equivalent to <c>Layer.InnerLegs</c>.
|
||||
/// </summary>
|
||||
LastUserValid = 0x18,
|
||||
|
||||
/// <summary>
|
||||
/// Mount item layer.
|
||||
/// </summary>
|
||||
Mount = 0x19,
|
||||
|
||||
/// <summary>
|
||||
/// Vendor 'buy pack' layer.
|
||||
/// </summary>
|
||||
ShopBuy = 0x1A,
|
||||
|
||||
/// <summary>
|
||||
/// Vendor 'resale pack' layer.
|
||||
/// </summary>
|
||||
ShopResale = 0x1B,
|
||||
|
||||
/// <summary>
|
||||
/// Vendor 'sell pack' layer.
|
||||
/// </summary>
|
||||
ShopSell = 0x1C,
|
||||
|
||||
/// <summary>
|
||||
/// Bank box layer.
|
||||
/// </summary>
|
||||
Bank = 0x1D,
|
||||
|
||||
/// <summary>
|
||||
/// Last valid layer. Equivalent to <c>Layer.Bank</c>.
|
||||
/// </summary>
|
||||
LastValid = 0x1D
|
||||
}
|
||||
}
|
||||
287
Projects/Server/LightType.cs
Normal file
287
Projects/Server/LightType.cs
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
namespace Server
|
||||
{
|
||||
public enum LightType
|
||||
{
|
||||
/// <summary>
|
||||
/// Window shape, arched, ray shining east.
|
||||
/// </summary>
|
||||
ArchedWindowEast,
|
||||
|
||||
/// <summary>
|
||||
/// Medium circular shape.
|
||||
/// </summary>
|
||||
Circle225,
|
||||
|
||||
/// <summary>
|
||||
/// Small circular shape.
|
||||
/// </summary>
|
||||
Circle150,
|
||||
|
||||
/// <summary>
|
||||
/// Door shape, shining south.
|
||||
/// </summary>
|
||||
DoorSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Door shape, shining east.
|
||||
/// </summary>
|
||||
DoorEast,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), north wall.
|
||||
/// </summary>
|
||||
NorthBig,
|
||||
|
||||
/// <summary>
|
||||
/// Large pie shape (90 degrees), north-east corner.
|
||||
/// </summary>
|
||||
NorthEastBig,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), east wall.
|
||||
/// </summary>
|
||||
EastBig,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), west wall.
|
||||
/// </summary>
|
||||
WestBig,
|
||||
|
||||
/// <summary>
|
||||
/// Large pie shape (90 degrees), south-west corner.
|
||||
/// </summary>
|
||||
SouthWestBig,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), south wall.
|
||||
/// </summary>
|
||||
SouthBig,
|
||||
|
||||
/// <summary>
|
||||
/// Medium semicircular shape (180 degrees), north wall.
|
||||
/// </summary>
|
||||
NorthSmall,
|
||||
|
||||
/// <summary>
|
||||
/// Medium pie shape (90 degrees), north-east corner.
|
||||
/// </summary>
|
||||
NorthEastSmall,
|
||||
|
||||
/// <summary>
|
||||
/// Medium semicircular shape (180 degrees), east wall.
|
||||
/// </summary>
|
||||
EastSmall,
|
||||
|
||||
/// <summary>
|
||||
/// Medium semicircular shape (180 degrees), west wall.
|
||||
/// </summary>
|
||||
WestSmall,
|
||||
|
||||
/// <summary>
|
||||
/// Medium semicircular shape (180 degrees), south wall.
|
||||
/// </summary>
|
||||
SouthSmall,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a wall decoration, north wall.
|
||||
/// </summary>
|
||||
DecorationNorth,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a wall decoration, north-east corner.
|
||||
/// </summary>
|
||||
DecorationNorthEast,
|
||||
|
||||
/// <summary>
|
||||
/// Small semicircular shape (180 degrees), east wall.
|
||||
/// </summary>
|
||||
EastTiny,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a wall decoration, west wall.
|
||||
/// </summary>
|
||||
DecorationWest,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a wall decoration, south-west corner.
|
||||
/// </summary>
|
||||
DecorationSouthWest,
|
||||
|
||||
/// <summary>
|
||||
/// Small semicircular shape (180 degrees), south wall.
|
||||
/// </summary>
|
||||
SouthTiny,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, rectangular, no ray, shining south.
|
||||
/// </summary>
|
||||
RectWindowSouthNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, rectangular, no ray, shining east.
|
||||
/// </summary>
|
||||
RectWindowEastNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, rectangular, ray shining south.
|
||||
/// </summary>
|
||||
RectWindowSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, rectangular, ray shining east.
|
||||
/// </summary>
|
||||
RectWindowEast,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, arched, no ray, shining south.
|
||||
/// </summary>
|
||||
ArchedWindowSouthNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, arched, no ray, shining east.
|
||||
/// </summary>
|
||||
ArchedWindowEastNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, arched, ray shining south.
|
||||
/// </summary>
|
||||
ArchedWindowSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Large circular shape.
|
||||
/// </summary>
|
||||
Circle300,
|
||||
|
||||
/// <summary>
|
||||
/// Large pie shape (90 degrees), north-west corner.
|
||||
/// </summary>
|
||||
NorthWestBig,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Medium pie shape (90 degrees), south-east corner.
|
||||
/// </summary>
|
||||
DarkSouthEast,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Medium semicircular shape (180 degrees), south wall.
|
||||
/// </summary>
|
||||
DarkSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Medium pie shape (90 degrees), north-west corner.
|
||||
/// </summary>
|
||||
DarkNorthWest,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Medium pie shape (90 degrees), south-east corner. Equivalent to <c>LightType.SouthEast</c>.
|
||||
/// </summary>
|
||||
DarkSouthEast2,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Medium circular shape (180 degrees), east wall.
|
||||
/// </summary>
|
||||
DarkEast,
|
||||
|
||||
/// <summary>
|
||||
/// Negative light. Large circular shape.
|
||||
/// </summary>
|
||||
DarkCircle300,
|
||||
|
||||
/// <summary>
|
||||
/// Opened door shape, shining south.
|
||||
/// </summary>
|
||||
DoorOpenSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Opened door shape, shining east.
|
||||
/// </summary>
|
||||
DoorOpenEast,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, square, ray shining east.
|
||||
/// </summary>
|
||||
SquareWindowEast,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, square, no ray, shining east.
|
||||
/// </summary>
|
||||
SquareWindowEastNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, square, ray shining south.
|
||||
/// </summary>
|
||||
SquareWindowSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, square, no ray, shining south.
|
||||
/// </summary>
|
||||
SquareWindowSouthNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Empty.
|
||||
/// </summary>
|
||||
Empty,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, skinny, no ray, shining south.
|
||||
/// </summary>
|
||||
SkinnyWindowSouthNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, skinny, ray shining east.
|
||||
/// </summary>
|
||||
SkinnyWindowEast,
|
||||
|
||||
/// <summary>
|
||||
/// Window shape, skinny, no ray, shining east.
|
||||
/// </summary>
|
||||
SkinnyWindowEastNoRay,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a hole, shining south.
|
||||
/// </summary>
|
||||
HoleSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a hole, shining south.
|
||||
/// </summary>
|
||||
HoleEast,
|
||||
|
||||
/// <summary>
|
||||
/// Large circular shape with a moongate graphic embedded.
|
||||
/// </summary>
|
||||
Moongate,
|
||||
|
||||
/// <summary>
|
||||
/// Unknown usage. Many rows of slightly angled lines.
|
||||
/// </summary>
|
||||
Strips,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a small hole, shining south.
|
||||
/// </summary>
|
||||
SmallHoleSouth,
|
||||
|
||||
/// <summary>
|
||||
/// Shaped like a small hole, shining east.
|
||||
/// </summary>
|
||||
SmallHoleEast,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), north wall. Identical graphic as <c>LightType.NorthBig</c>, but slightly different
|
||||
/// positioning.
|
||||
/// </summary>
|
||||
NorthBig2,
|
||||
|
||||
/// <summary>
|
||||
/// Large semicircular shape (180 degrees), west wall. Identical graphic as <c>LightType.WestBig</c>, but slightly different
|
||||
/// positioning.
|
||||
/// </summary>
|
||||
WestBig2,
|
||||
|
||||
/// <summary>
|
||||
/// Large pie shape (90 degrees), north-west corner. Equivalent to <c>LightType.NorthWestBig</c>.
|
||||
/// </summary>
|
||||
NorthWestBig2
|
||||
}
|
||||
}
|
||||
724
Projects/Server/Main.cs
Normal file
724
Projects/Server/Main.cs
Normal file
|
|
@ -0,0 +1,724 @@
|
|||
/***************************************************************************
|
||||
* Main.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public delegate void Slice();
|
||||
|
||||
public static class Core
|
||||
{
|
||||
private static bool m_Crashed;
|
||||
private static Thread timerThread;
|
||||
private static string m_BaseDirectory;
|
||||
private static string m_ExePath;
|
||||
|
||||
private static bool m_Cache = true;
|
||||
|
||||
private static bool m_Profiling;
|
||||
private static DateTime m_ProfileStart;
|
||||
private static TimeSpan m_ProfileTime;
|
||||
|
||||
public static Slice Slice;
|
||||
|
||||
/*
|
||||
* DateTime.Now and DateTime.UtcNow are based on actual system clock time.
|
||||
* The resolution is acceptable but large clock jumps are possible and cause issues.
|
||||
* GetTickCount and GetTickCount64 have poor resolution.
|
||||
* GetTickCount64 is unavailable on Windows XP and Windows Server 2003.
|
||||
* Stopwatch.GetTimestamp() (QueryPerformanceCounter) is high resolution, but
|
||||
* somewhat expensive to call because of its defference to DateTime.Now,
|
||||
* which is why Stopwatch has been used to verify HRT before calling GetTimestamp(),
|
||||
* enabling the usage of DateTime.UtcNow instead.
|
||||
*/
|
||||
|
||||
private static readonly bool _HighRes = Stopwatch.IsHighResolution;
|
||||
|
||||
private static readonly double _HighFrequency = 1000.0 / Stopwatch.Frequency;
|
||||
private static readonly double _LowFrequency = 1000.0 / TimeSpan.TicksPerSecond;
|
||||
|
||||
private static bool _UseHRT;
|
||||
|
||||
public static readonly bool Is64Bit = Environment.Is64BitProcess;
|
||||
internal static ConsoleEventHandler m_ConsoleEventHandler;
|
||||
|
||||
private static int m_CycleIndex = 1;
|
||||
private static readonly float[] m_CyclesPerSecond = new float[100];
|
||||
|
||||
private static readonly AutoResetEvent m_Signal = new AutoResetEvent(true);
|
||||
|
||||
private static int m_ItemCount, m_MobileCount;
|
||||
|
||||
private static readonly Type[] m_SerialTypeArray = { typeof(Serial) };
|
||||
|
||||
public static MessagePump MessagePump{ get; set; }
|
||||
|
||||
public static bool Profiling
|
||||
{
|
||||
get => m_Profiling;
|
||||
set
|
||||
{
|
||||
if (m_Profiling == value)
|
||||
return;
|
||||
|
||||
m_Profiling = value;
|
||||
|
||||
if (m_ProfileStart > DateTime.MinValue)
|
||||
m_ProfileTime += DateTime.UtcNow - m_ProfileStart;
|
||||
|
||||
m_ProfileStart = m_Profiling ? DateTime.UtcNow : DateTime.MinValue;
|
||||
}
|
||||
}
|
||||
|
||||
public static TimeSpan ProfileTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_ProfileStart > DateTime.MinValue)
|
||||
return m_ProfileTime + (DateTime.UtcNow - m_ProfileStart);
|
||||
|
||||
return m_ProfileTime;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Service{ get; private set; }
|
||||
|
||||
public static bool Debug { get; private set; }
|
||||
|
||||
internal static bool HaltOnWarning{ get; private set; }
|
||||
|
||||
public static List<string> DataDirectories{ get; } = new List<string>();
|
||||
|
||||
public static Assembly Assembly{ get; set; }
|
||||
|
||||
public static Version Version => Assembly.GetName().Version;
|
||||
public static Process Process{ get; private set; }
|
||||
|
||||
public static Thread Thread{ get; private set; }
|
||||
|
||||
public static MultiTextWriter MultiConsoleOut{ get; private set; }
|
||||
|
||||
public static bool UsingHighResolutionTiming => _UseHRT && _HighRes && !Unix;
|
||||
|
||||
public static long TickCount => (long)Ticks;
|
||||
|
||||
public static double Ticks
|
||||
{
|
||||
get
|
||||
{
|
||||
if (_UseHRT && _HighRes && !Unix) return Stopwatch.GetTimestamp() * _HighFrequency;
|
||||
|
||||
return DateTime.UtcNow.Ticks * _LowFrequency;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool MultiProcessor{ get; private set; }
|
||||
|
||||
public static int ProcessorCount{ get; private set; }
|
||||
|
||||
public static bool Unix{ get; private set; }
|
||||
|
||||
public static string ExePath => m_ExePath ?? (m_ExePath = Assembly.Location);
|
||||
|
||||
public static string BaseDirectory
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_BaseDirectory == null)
|
||||
try
|
||||
{
|
||||
m_BaseDirectory = ExePath;
|
||||
|
||||
if (m_BaseDirectory.Length > 0)
|
||||
m_BaseDirectory = Path.GetDirectoryName(m_BaseDirectory);
|
||||
}
|
||||
catch
|
||||
{
|
||||
m_BaseDirectory = "";
|
||||
}
|
||||
|
||||
return m_BaseDirectory;
|
||||
}
|
||||
}
|
||||
|
||||
public static bool Closing{ get; private set; }
|
||||
|
||||
public static float CyclesPerSecond => m_CyclesPerSecond[(m_CycleIndex - 1) % m_CyclesPerSecond.Length];
|
||||
|
||||
public static float AverageCPS => m_CyclesPerSecond.Take(m_CycleIndex).Average();
|
||||
|
||||
public static string Arguments
|
||||
{
|
||||
get
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (Debug)
|
||||
Utility.Separate(sb, "-debug", " ");
|
||||
|
||||
if (Service)
|
||||
Utility.Separate(sb, "-service", " ");
|
||||
|
||||
if (m_Profiling)
|
||||
Utility.Separate(sb, "-profile", " ");
|
||||
|
||||
if (!m_Cache)
|
||||
Utility.Separate(sb, "-nocache", " ");
|
||||
|
||||
if (HaltOnWarning)
|
||||
Utility.Separate(sb, "-haltonwarning", " ");
|
||||
|
||||
if (_UseHRT)
|
||||
Utility.Separate(sb, "-usehrt", " ");
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public static int GlobalUpdateRange{ get; set; } = 18;
|
||||
|
||||
public static int GlobalMaxUpdateRange{ get; set; } = 24;
|
||||
|
||||
public static int ScriptItems => m_ItemCount;
|
||||
public static int ScriptMobiles => m_MobileCount;
|
||||
|
||||
public static string FindDataFile(string path)
|
||||
{
|
||||
if (DataDirectories.Count == 0)
|
||||
throw new InvalidOperationException(
|
||||
"Attempted to FindDataFile before DataDirectories list has been filled.");
|
||||
|
||||
string fullPath = null;
|
||||
|
||||
foreach (string p in DataDirectories)
|
||||
{
|
||||
fullPath = Path.Combine(p, path);
|
||||
|
||||
if (File.Exists(fullPath))
|
||||
break;
|
||||
|
||||
fullPath = null;
|
||||
}
|
||||
|
||||
return fullPath;
|
||||
}
|
||||
|
||||
public static string FindDataFile(string format, params object[] args)
|
||||
{
|
||||
return FindDataFile(string.Format(format, args));
|
||||
}
|
||||
|
||||
private static void CurrentDomain_UnhandledException(object sender, UnhandledExceptionEventArgs e)
|
||||
{
|
||||
Console.WriteLine(e.IsTerminating ? "Error:" : "Warning:");
|
||||
Console.WriteLine(e.ExceptionObject);
|
||||
|
||||
if (e.IsTerminating)
|
||||
{
|
||||
m_Crashed = true;
|
||||
|
||||
bool close = false;
|
||||
|
||||
try
|
||||
{
|
||||
CrashedEventArgs args = new CrashedEventArgs(e.ExceptionObject as Exception);
|
||||
|
||||
EventSink.InvokeCrashed(args);
|
||||
|
||||
close = args.Close;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
if (!close && !Service)
|
||||
{
|
||||
try
|
||||
{
|
||||
foreach (Listener l in MessagePump.Listeners)
|
||||
l.Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Console.WriteLine("This exception is fatal, press return to exit");
|
||||
Console.ReadLine();
|
||||
}
|
||||
|
||||
Kill();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool OnConsoleEvent(ConsoleEventType type)
|
||||
{
|
||||
if (World.Saving || Service && type == ConsoleEventType.CTRL_LOGOFF_EVENT)
|
||||
return true;
|
||||
|
||||
Kill(); //Kill -> HandleClosed will handle waiting for the completion of flushing to disk
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static void CurrentDomain_ProcessExit(object sender, EventArgs e)
|
||||
{
|
||||
HandleClosed();
|
||||
}
|
||||
|
||||
public static void Kill()
|
||||
{
|
||||
Kill(false);
|
||||
}
|
||||
|
||||
public static void Kill(bool restart)
|
||||
{
|
||||
HandleClosed();
|
||||
|
||||
if (restart)
|
||||
Process.Start(ExePath, Arguments);
|
||||
|
||||
Process.Kill();
|
||||
}
|
||||
|
||||
private static void HandleClosed()
|
||||
{
|
||||
if (Closing)
|
||||
return;
|
||||
|
||||
Closing = true;
|
||||
|
||||
Console.WriteLine("Exiting...");
|
||||
|
||||
World.WaitForWriteCompletion();
|
||||
|
||||
if (!m_Crashed)
|
||||
EventSink.InvokeShutdown(new ShutdownEventArgs());
|
||||
|
||||
Timer.TimerThread.Set();
|
||||
|
||||
Console.WriteLine("done");
|
||||
}
|
||||
|
||||
public static void Set()
|
||||
{
|
||||
m_Signal.Set();
|
||||
}
|
||||
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
|
||||
AppDomain.CurrentDomain.ProcessExit += CurrentDomain_ProcessExit;
|
||||
|
||||
foreach (string a in args)
|
||||
if (Insensitive.Equals(a, "-debug"))
|
||||
Debug = true;
|
||||
else if (Insensitive.Equals(a, "-service"))
|
||||
Service = true;
|
||||
else if (Insensitive.Equals(a, "-profile"))
|
||||
Profiling = true;
|
||||
else if (Insensitive.Equals(a, "-nocache"))
|
||||
m_Cache = false;
|
||||
else if (Insensitive.Equals(a, "-haltonwarning"))
|
||||
HaltOnWarning = true;
|
||||
else if (Insensitive.Equals(a, "-usehrt"))
|
||||
_UseHRT = true;
|
||||
|
||||
try
|
||||
{
|
||||
if (Service)
|
||||
{
|
||||
if (!Directory.Exists("Logs"))
|
||||
Directory.CreateDirectory("Logs");
|
||||
|
||||
Console.SetOut(MultiConsoleOut = new MultiTextWriter(new FileLogger("Logs/Console.log")));
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.SetOut(MultiConsoleOut = new MultiTextWriter(Console.Out));
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Thread = Thread.CurrentThread;
|
||||
Process = Process.GetCurrentProcess();
|
||||
Assembly = Assembly.GetEntryAssembly();
|
||||
|
||||
if (Thread != null)
|
||||
Thread.Name = "Core Thread";
|
||||
|
||||
if (BaseDirectory.Length > 0)
|
||||
Directory.SetCurrentDirectory(BaseDirectory);
|
||||
|
||||
Timer.TimerThread ttObj = new Timer.TimerThread();
|
||||
timerThread = new Thread(ttObj.TimerMain)
|
||||
{
|
||||
Name = "Timer Thread"
|
||||
};
|
||||
|
||||
Version ver = Assembly.GetName().Version;
|
||||
|
||||
// Added to help future code support on forums, as a 'check' people can ask for to it see if they recompiled core or not
|
||||
Console.WriteLine("ModernUO - [https://github.com/kamronbatman/ModernUO] Version {0}.{1}.{2}.{3}", ver.Major, ver.Minor, ver.Build,
|
||||
ver.Revision);
|
||||
#if NETCORE
|
||||
Console.WriteLine("Core: Running on {0}", RuntimeInformation.FrameworkDescription);
|
||||
#else
|
||||
Console.WriteLine("Core: Running on .NET Framework Version {0}.{1}.{2}", Environment.Version.Major,
|
||||
Environment.Version.Minor, Environment.Version.Build);
|
||||
#endif
|
||||
|
||||
string s = Arguments;
|
||||
|
||||
if (s.Length > 0)
|
||||
Console.WriteLine("Core: Running with arguments: {0}", s);
|
||||
|
||||
ProcessorCount = Environment.ProcessorCount;
|
||||
|
||||
if (ProcessorCount > 1)
|
||||
MultiProcessor = true;
|
||||
|
||||
if (MultiProcessor || Is64Bit)
|
||||
Console.WriteLine("Core: Optimizing for {0} {2}processor{1}", ProcessorCount, ProcessorCount == 1 ? "" : "s",
|
||||
Is64Bit ? "64-bit " : "");
|
||||
|
||||
int platform = (int)Environment.OSVersion.Platform;
|
||||
if (platform == 4 || platform == 128)
|
||||
{
|
||||
// MS 4, MONO 128
|
||||
Unix = true;
|
||||
Console.WriteLine("Core: Unix environment detected");
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ConsoleEventHandler = OnConsoleEvent;
|
||||
UnsafeNativeMethods.SetConsoleCtrlHandler(m_ConsoleEventHandler, true);
|
||||
}
|
||||
|
||||
if (GCSettings.IsServerGC)
|
||||
Console.WriteLine("Core: Server garbage collection mode enabled");
|
||||
|
||||
if (_UseHRT)
|
||||
Console.WriteLine("Core: Requested high resolution timing ({0})",
|
||||
UsingHighResolutionTiming ? "Supported" : "Unsupported");
|
||||
|
||||
Console.WriteLine("RandomImpl: {0} ({1})", RandomImpl.Type.Name,
|
||||
RandomImpl.IsHardwareRNG ? "Hardware" : "Software");
|
||||
|
||||
// Load Assembly Scripts.CS.dll
|
||||
ScriptCompiler.LoadScripts();
|
||||
|
||||
ScriptCompiler.Invoke("Configure");
|
||||
|
||||
Region.Load();
|
||||
World.Load();
|
||||
|
||||
ScriptCompiler.Invoke("Initialize");
|
||||
|
||||
// Start accepting new connections
|
||||
MessagePump = new MessagePump();
|
||||
|
||||
ScriptCompiler.Invoke("RegisterListeners");
|
||||
|
||||
timerThread.Start();
|
||||
|
||||
foreach (Map m in Map.AllMaps)
|
||||
m.Tiles.Force();
|
||||
|
||||
NetState.Initialize();
|
||||
|
||||
EventSink.InvokeServerStarted();
|
||||
|
||||
try
|
||||
{
|
||||
long last = TickCount;
|
||||
|
||||
const int sampleInterval = 100;
|
||||
const float ticksPerSecond = 1000.0f * sampleInterval;
|
||||
|
||||
long sample = 0;
|
||||
|
||||
while (!Closing)
|
||||
{
|
||||
m_Signal.WaitOne();
|
||||
|
||||
Task.WaitAll(
|
||||
Task.Run(() => Mobile.ProcessDeltaQueue()),
|
||||
Task.Run(() => Item.ProcessDeltaQueue()),
|
||||
Task.Run(() => Timer.Slice()),
|
||||
Task.Run(() => MessagePump.DoWork())
|
||||
);
|
||||
|
||||
NetState.ProcessDisposedQueue();
|
||||
|
||||
Slice?.Invoke();
|
||||
|
||||
if (sample++ % sampleInterval != 0)
|
||||
continue;
|
||||
|
||||
long now = TickCount;
|
||||
m_CyclesPerSecond[m_CycleIndex++ % m_CyclesPerSecond.Length] = ticksPerSecond / (now - last);
|
||||
last = now;
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
CurrentDomain_UnhandledException(null, new UnhandledExceptionEventArgs(e, true));
|
||||
}
|
||||
}
|
||||
|
||||
public static void VerifySerialization()
|
||||
{
|
||||
m_ItemCount = 0;
|
||||
m_MobileCount = 0;
|
||||
|
||||
Assembly ca = Assembly.GetCallingAssembly();
|
||||
|
||||
VerifySerialization(ca);
|
||||
|
||||
foreach (Assembly a in ScriptCompiler.Assemblies.Where(a => a != ca)) VerifySerialization(a);
|
||||
}
|
||||
|
||||
private static void VerifyType(Type t)
|
||||
{
|
||||
bool isItem = t.IsSubclassOf(typeof(Item));
|
||||
|
||||
if (!isItem && !t.IsSubclassOf(typeof(Mobile))) return;
|
||||
|
||||
if (isItem)
|
||||
Interlocked.Increment(ref m_ItemCount);
|
||||
else
|
||||
Interlocked.Increment(ref m_MobileCount);
|
||||
|
||||
StringBuilder warningSb = null;
|
||||
|
||||
try
|
||||
{
|
||||
if (t.GetConstructor(m_SerialTypeArray) == null)
|
||||
{
|
||||
warningSb = new StringBuilder();
|
||||
|
||||
warningSb.AppendLine(" - No serialization constructor");
|
||||
}
|
||||
|
||||
if (
|
||||
t.GetMethod(
|
||||
"Serialize",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) ==
|
||||
null)
|
||||
{
|
||||
if (warningSb == null) warningSb = new StringBuilder();
|
||||
|
||||
warningSb.AppendLine(" - No Serialize() method");
|
||||
}
|
||||
|
||||
if (
|
||||
t.GetMethod(
|
||||
"Deserialize",
|
||||
BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly) ==
|
||||
null)
|
||||
{
|
||||
if (warningSb == null) warningSb = new StringBuilder();
|
||||
|
||||
warningSb.AppendLine(" - No Deserialize() method");
|
||||
}
|
||||
|
||||
if (warningSb?.Length > 0) Console.WriteLine("Warning: {0}\n{1}", t, warningSb);
|
||||
}
|
||||
catch
|
||||
{
|
||||
Console.WriteLine("Warning: Exception in serialization verification of type {0}", t);
|
||||
}
|
||||
}
|
||||
|
||||
private static void VerifySerialization(Assembly a)
|
||||
{
|
||||
if (a != null) Parallel.ForEach(a.GetTypes(), VerifyType);
|
||||
}
|
||||
|
||||
internal enum ConsoleEventType
|
||||
{
|
||||
CTRL_C_EVENT,
|
||||
CTRL_BREAK_EVENT,
|
||||
CTRL_CLOSE_EVENT,
|
||||
CTRL_LOGOFF_EVENT = 5,
|
||||
CTRL_SHUTDOWN_EVENT
|
||||
}
|
||||
|
||||
internal delegate bool ConsoleEventHandler(ConsoleEventType type);
|
||||
|
||||
internal class UnsafeNativeMethods
|
||||
{
|
||||
[DllImport("Kernel32")]
|
||||
internal static extern bool SetConsoleCtrlHandler(ConsoleEventHandler callback, bool add);
|
||||
}
|
||||
|
||||
#region Expansions
|
||||
|
||||
public static Expansion Expansion{ get; set; }
|
||||
|
||||
public static bool T2A => Expansion >= Expansion.T2A;
|
||||
|
||||
public static bool UOR => Expansion >= Expansion.UOR;
|
||||
|
||||
public static bool UOTD => Expansion >= Expansion.UOTD;
|
||||
|
||||
public static bool LBR => Expansion >= Expansion.LBR;
|
||||
|
||||
public static bool AOS => Expansion >= Expansion.AOS;
|
||||
|
||||
public static bool SE => Expansion >= Expansion.SE;
|
||||
|
||||
public static bool ML => Expansion >= Expansion.ML;
|
||||
|
||||
public static bool SA => Expansion >= Expansion.SA;
|
||||
|
||||
public static bool HS => Expansion >= Expansion.HS;
|
||||
|
||||
public static bool TOL => Expansion >= Expansion.TOL;
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public class FileLogger : TextWriter
|
||||
{
|
||||
public const string DateFormat = "[MMMM dd hh:mm:ss.f tt]: ";
|
||||
|
||||
private bool _NewLine;
|
||||
|
||||
public FileLogger(string file, bool append = false)
|
||||
{
|
||||
FileName = file;
|
||||
|
||||
using (
|
||||
StreamWriter writer =
|
||||
new StreamWriter(
|
||||
new FileStream(FileName, append ? FileMode.Append : FileMode.Create, FileAccess.Write,
|
||||
FileShare.Read)))
|
||||
{
|
||||
writer.WriteLine(">>>Logging started on {0}.", DateTime.UtcNow.ToString("f"));
|
||||
//f = Tuesday, April 10, 2001 3:51 PM
|
||||
}
|
||||
|
||||
_NewLine = true;
|
||||
}
|
||||
|
||||
public string FileName{ get; }
|
||||
|
||||
public override Encoding Encoding => Encoding.Default;
|
||||
|
||||
public override void Write(char ch)
|
||||
{
|
||||
using (StreamWriter writer =
|
||||
new StreamWriter(new FileStream(FileName, FileMode.Append, FileAccess.Write, FileShare.Read)))
|
||||
{
|
||||
if (_NewLine)
|
||||
{
|
||||
writer.Write(DateTime.UtcNow.ToString(DateFormat));
|
||||
_NewLine = false;
|
||||
}
|
||||
|
||||
writer.Write(ch);
|
||||
}
|
||||
}
|
||||
|
||||
public override void Write(string str)
|
||||
{
|
||||
using (StreamWriter writer =
|
||||
new StreamWriter(new FileStream(FileName, FileMode.Append, FileAccess.Write, FileShare.Read)))
|
||||
{
|
||||
if (_NewLine)
|
||||
{
|
||||
writer.Write(DateTime.UtcNow.ToString(DateFormat));
|
||||
_NewLine = false;
|
||||
}
|
||||
|
||||
writer.Write(str);
|
||||
}
|
||||
}
|
||||
|
||||
public override void WriteLine(string line)
|
||||
{
|
||||
using (StreamWriter writer =
|
||||
new StreamWriter(new FileStream(FileName, FileMode.Append, FileAccess.Write, FileShare.Read)))
|
||||
{
|
||||
if (_NewLine) writer.Write(DateTime.UtcNow.ToString(DateFormat));
|
||||
|
||||
writer.WriteLine(line);
|
||||
_NewLine = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class MultiTextWriter : TextWriter
|
||||
{
|
||||
private readonly List<TextWriter> _Streams;
|
||||
|
||||
public MultiTextWriter(params TextWriter[] streams)
|
||||
{
|
||||
_Streams = new List<TextWriter>(streams);
|
||||
|
||||
if (_Streams.Count < 0) throw new ArgumentException("You must specify at least one stream.");
|
||||
}
|
||||
|
||||
public override Encoding Encoding => Encoding.Default;
|
||||
|
||||
public void Add(TextWriter tw)
|
||||
{
|
||||
_Streams.Add(tw);
|
||||
}
|
||||
|
||||
public void Remove(TextWriter tw)
|
||||
{
|
||||
_Streams.Remove(tw);
|
||||
}
|
||||
|
||||
public override void Write(char ch)
|
||||
{
|
||||
foreach (TextWriter t in _Streams) t.Write(ch);
|
||||
}
|
||||
|
||||
public override void WriteLine(string line)
|
||||
{
|
||||
foreach (TextWriter t in _Streams) t.WriteLine(line);
|
||||
}
|
||||
|
||||
public override void WriteLine(string line, params object[] args)
|
||||
{
|
||||
WriteLine(string.Format(line, args));
|
||||
}
|
||||
}
|
||||
}
|
||||
1586
Projects/Server/Map.cs
Normal file
1586
Projects/Server/Map.cs
Normal file
File diff suppressed because it is too large
Load diff
33
Projects/Server/Menus/IMenu.cs
Normal file
33
Projects/Server/Menus/IMenu.cs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
/***************************************************************************
|
||||
* IMenu.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 Server.Network;
|
||||
|
||||
namespace Server.Menus
|
||||
{
|
||||
public interface IMenu
|
||||
{
|
||||
int Serial{ get; }
|
||||
int EntryLength{ get; }
|
||||
void SendTo(NetState state);
|
||||
void OnCancel(NetState state);
|
||||
void OnResponse(NetState state, int index);
|
||||
}
|
||||
}
|
||||
82
Projects/Server/Menus/ItemListMenu.cs
Normal file
82
Projects/Server/Menus/ItemListMenu.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* ItemListMenu.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 Server.Network;
|
||||
|
||||
namespace Server.Menus.ItemLists
|
||||
{
|
||||
public class ItemListEntry
|
||||
{
|
||||
public ItemListEntry(string name, int itemID, int hue = 0)
|
||||
{
|
||||
Name = name;
|
||||
ItemID = itemID;
|
||||
Hue = hue;
|
||||
}
|
||||
|
||||
public string Name{ get; }
|
||||
|
||||
public int ItemID{ get; }
|
||||
|
||||
public int Hue{ get; }
|
||||
}
|
||||
|
||||
public class ItemListMenu : IMenu
|
||||
{
|
||||
private static int m_NextSerial;
|
||||
private int m_Serial;
|
||||
|
||||
public ItemListMenu(string question, ItemListEntry[] entries)
|
||||
{
|
||||
Question = question;
|
||||
Entries = entries;
|
||||
|
||||
do
|
||||
{
|
||||
m_Serial = m_NextSerial++;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while (m_Serial == 0);
|
||||
|
||||
m_Serial = (int)((uint)m_Serial | 0x80000000);
|
||||
}
|
||||
|
||||
public string Question{ get; }
|
||||
|
||||
public ItemListEntry[] Entries{ get; set; }
|
||||
|
||||
int IMenu.Serial => m_Serial;
|
||||
|
||||
int IMenu.EntryLength => Entries.Length;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
64
Projects/Server/Menus/QuestionMenu.cs
Normal file
64
Projects/Server/Menus/QuestionMenu.cs
Normal file
|
|
@ -0,0 +1,64 @@
|
|||
/***************************************************************************
|
||||
* QuestionMenu.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 Server.Network;
|
||||
|
||||
namespace Server.Menus.Questions
|
||||
{
|
||||
public class QuestionMenu : IMenu
|
||||
{
|
||||
private static int m_NextSerial;
|
||||
private int m_Serial;
|
||||
|
||||
public QuestionMenu(string question, string[] answers)
|
||||
{
|
||||
Question = question;
|
||||
Answers = answers;
|
||||
|
||||
do
|
||||
{
|
||||
m_Serial = ++m_NextSerial;
|
||||
m_Serial &= 0x7FFFFFFF;
|
||||
} while (m_Serial == 0);
|
||||
}
|
||||
|
||||
public string Question{ get; set; }
|
||||
|
||||
public string[] Answers{ get; }
|
||||
|
||||
int IMenu.Serial => m_Serial;
|
||||
|
||||
int IMenu.EntryLength => Answers.Length;
|
||||
|
||||
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));
|
||||
}
|
||||
}
|
||||
}
|
||||
9902
Projects/Server/Mobile.cs
Normal file
9902
Projects/Server/Mobile.cs
Normal file
File diff suppressed because it is too large
Load diff
86
Projects/Server/Movement.cs
Normal file
86
Projects/Server/Movement.cs
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
/***************************************************************************
|
||||
* Movement.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.Movement
|
||||
{
|
||||
public static class Movement
|
||||
{
|
||||
public static IMovementImpl Impl{ get; set; }
|
||||
|
||||
public static bool CheckMovement(Mobile m, Direction d, out int newZ)
|
||||
{
|
||||
if (Impl != null)
|
||||
return Impl.CheckMovement(m, d, out newZ);
|
||||
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ)
|
||||
{
|
||||
if (Impl != null)
|
||||
return Impl.CheckMovement(m, map, loc, d, out newZ);
|
||||
|
||||
newZ = m.Z;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void Offset(Direction d, ref int x, ref int y)
|
||||
{
|
||||
switch (d & Direction.Mask)
|
||||
{
|
||||
case Direction.North:
|
||||
--y;
|
||||
break;
|
||||
case Direction.South:
|
||||
++y;
|
||||
break;
|
||||
case Direction.West:
|
||||
--x;
|
||||
break;
|
||||
case Direction.East:
|
||||
++x;
|
||||
break;
|
||||
case Direction.Right:
|
||||
++x;
|
||||
--y;
|
||||
break;
|
||||
case Direction.Left:
|
||||
--x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Down:
|
||||
++x;
|
||||
++y;
|
||||
break;
|
||||
case Direction.Up:
|
||||
--x;
|
||||
--y;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IMovementImpl
|
||||
{
|
||||
bool CheckMovement(Mobile m, Direction d, out int newZ);
|
||||
bool CheckMovement(Mobile m, Map map, Point3D loc, Direction d, out int newZ);
|
||||
}
|
||||
}
|
||||
583
Projects/Server/MultiData.cs
Normal file
583
Projects/Server/MultiData.cs
Normal file
|
|
@ -0,0 +1,583 @@
|
|||
/***************************************************************************
|
||||
* MultiData.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class MultiData
|
||||
{
|
||||
private static MultiComponentList[] m_Components;
|
||||
|
||||
private static FileStream m_Index, m_Stream;
|
||||
private static BinaryReader m_IndexReader, m_StreamReader;
|
||||
|
||||
static MultiData()
|
||||
{
|
||||
string idxPath = Core.FindDataFile("multi.idx");
|
||||
string mulPath = Core.FindDataFile("multi.mul");
|
||||
|
||||
if (File.Exists(idxPath) && File.Exists(mulPath))
|
||||
{
|
||||
m_Index = new FileStream(idxPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
m_IndexReader = new BinaryReader(m_Index);
|
||||
|
||||
m_Stream = new FileStream(mulPath, FileMode.Open, FileAccess.Read, FileShare.Read);
|
||||
m_StreamReader = new BinaryReader(m_Stream);
|
||||
|
||||
m_Components = new MultiComponentList[(int)(m_Index.Length / 12)];
|
||||
|
||||
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 && index < m_Components.Length && 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");
|
||||
|
||||
m_Components = new MultiComponentList[0];
|
||||
}
|
||||
}
|
||||
|
||||
public static MultiComponentList GetComponents(int multiID)
|
||||
{
|
||||
MultiComponentList mcl;
|
||||
|
||||
if (multiID >= 0 && multiID < m_Components.Length)
|
||||
{
|
||||
mcl = m_Components[multiID];
|
||||
|
||||
if (mcl == null)
|
||||
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 struct MultiTileEntry
|
||||
{
|
||||
public ushort m_ItemID;
|
||||
public short m_OffsetX, m_OffsetY, m_OffsetZ;
|
||||
public int m_Flags;
|
||||
|
||||
public MultiTileEntry(ushort itemID, short xOffset, short yOffset, short zOffset, int flags)
|
||||
{
|
||||
m_ItemID = itemID;
|
||||
m_OffsetX = xOffset;
|
||||
m_OffsetY = yOffset;
|
||||
m_OffsetZ = zOffset;
|
||||
m_Flags = flags;
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class MultiComponentList
|
||||
{
|
||||
public static readonly MultiComponentList Empty = new MultiComponentList();
|
||||
|
||||
private Point2D m_Min, m_Max;
|
||||
|
||||
public MultiComponentList(MultiComponentList toCopy)
|
||||
{
|
||||
m_Min = toCopy.m_Min;
|
||||
m_Max = toCopy.m_Max;
|
||||
|
||||
Center = toCopy.Center;
|
||||
|
||||
Width = toCopy.Width;
|
||||
Height = toCopy.Height;
|
||||
|
||||
Tiles = new StaticTile[Width][][];
|
||||
|
||||
for (int x = 0; x < Width; ++x)
|
||||
{
|
||||
Tiles[x] = new StaticTile[Height][];
|
||||
|
||||
for (int y = 0; y < Height; ++y)
|
||||
{
|
||||
Tiles[x][y] = new StaticTile[toCopy.Tiles[x][y].Length];
|
||||
|
||||
for (int i = 0; i < Tiles[x][y].Length; ++i)
|
||||
Tiles[x][y][i] = toCopy.Tiles[x][y][i];
|
||||
}
|
||||
}
|
||||
|
||||
List = new MultiTileEntry[toCopy.List.Length];
|
||||
|
||||
for (int i = 0; i < List.Length; ++i)
|
||||
List[i] = toCopy.List[i];
|
||||
}
|
||||
|
||||
public MultiComponentList(GenericReader reader)
|
||||
{
|
||||
int version = reader.ReadInt();
|
||||
|
||||
m_Min = reader.ReadPoint2D();
|
||||
m_Max = reader.ReadPoint2D();
|
||||
Center = reader.ReadPoint2D();
|
||||
Width = reader.ReadInt();
|
||||
Height = reader.ReadInt();
|
||||
|
||||
int length = reader.ReadInt();
|
||||
|
||||
MultiTileEntry[] allTiles = 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 = reader.ReadInt();
|
||||
}
|
||||
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();
|
||||
allTiles[i].m_Flags = reader.ReadInt();
|
||||
}
|
||||
|
||||
TileList[][] tiles = new TileList[Width][];
|
||||
Tiles = new StaticTile[Width][][];
|
||||
|
||||
for (int x = 0; x < Width; ++x)
|
||||
{
|
||||
tiles[x] = new TileList[Height];
|
||||
Tiles[x] = new StaticTile[Height][];
|
||||
|
||||
for (int y = 0; y < Height; ++y)
|
||||
tiles[x][y] = new TileList();
|
||||
}
|
||||
|
||||
for (int i = 0; i < allTiles.Length; ++i)
|
||||
if (i == 0 || allTiles[i].m_Flags != 0)
|
||||
{
|
||||
int xOffset = allTiles[i].m_OffsetX + Center.m_X;
|
||||
int yOffset = allTiles[i].m_OffsetY + Center.m_Y;
|
||||
|
||||
tiles[xOffset][yOffset].Add(allTiles[i].m_ItemID, (sbyte)allTiles[i].m_OffsetZ);
|
||||
}
|
||||
|
||||
for (int x = 0; x < Width; ++x)
|
||||
for (int y = 0; y < Height; ++y)
|
||||
Tiles[x][y] = tiles[x][y].ToArray();
|
||||
}
|
||||
|
||||
public MultiComponentList(BinaryReader reader, int count)
|
||||
{
|
||||
MultiTileEntry[] allTiles = 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();
|
||||
allTiles[i].m_Flags = reader.ReadInt32();
|
||||
|
||||
if (PostHSFormat)
|
||||
reader.ReadInt32(); // ??
|
||||
|
||||
MultiTileEntry e = allTiles[i];
|
||||
|
||||
if (i == 0 || e.m_Flags != 0)
|
||||
{
|
||||
if (e.m_OffsetX < m_Min.m_X)
|
||||
m_Min.m_X = e.m_OffsetX;
|
||||
|
||||
if (e.m_OffsetY < m_Min.m_Y)
|
||||
m_Min.m_Y = e.m_OffsetY;
|
||||
|
||||
if (e.m_OffsetX > m_Max.m_X)
|
||||
m_Max.m_X = e.m_OffsetX;
|
||||
|
||||
if (e.m_OffsetY > m_Max.m_Y)
|
||||
m_Max.m_Y = e.m_OffsetY;
|
||||
}
|
||||
}
|
||||
|
||||
Center = new Point2D(-m_Min.m_X, -m_Min.m_Y);
|
||||
Width = m_Max.m_X - m_Min.m_X + 1;
|
||||
Height = m_Max.m_Y - m_Min.m_Y + 1;
|
||||
|
||||
TileList[][] tiles = new TileList[Width][];
|
||||
Tiles = new StaticTile[Width][][];
|
||||
|
||||
for (int x = 0; x < Width; ++x)
|
||||
{
|
||||
tiles[x] = new TileList[Height];
|
||||
Tiles[x] = new StaticTile[Height][];
|
||||
|
||||
for (int y = 0; y < Height; ++y)
|
||||
tiles[x][y] = new TileList();
|
||||
}
|
||||
|
||||
for (int i = 0; i < allTiles.Length; ++i)
|
||||
if (i == 0 || allTiles[i].m_Flags != 0)
|
||||
{
|
||||
int xOffset = allTiles[i].m_OffsetX + Center.m_X;
|
||||
int yOffset = allTiles[i].m_OffsetY + Center.m_Y;
|
||||
|
||||
tiles[xOffset][yOffset].Add(allTiles[i].m_ItemID, (sbyte)allTiles[i].m_OffsetZ);
|
||||
}
|
||||
|
||||
for (int x = 0; x < Width; ++x)
|
||||
for (int y = 0; y < Height; ++y)
|
||||
Tiles[x][y] = tiles[x][y].ToArray();
|
||||
}
|
||||
|
||||
private MultiComponentList()
|
||||
{
|
||||
Tiles = new StaticTile[0][][];
|
||||
List = new MultiTileEntry[0];
|
||||
}
|
||||
|
||||
public static bool PostHSFormat{ get; set; }
|
||||
|
||||
public Point2D Min => m_Min;
|
||||
public Point2D Max => m_Max;
|
||||
|
||||
public Point2D Center{ get; }
|
||||
|
||||
public int Width{ get; private set; }
|
||||
|
||||
public int Height{ get; private set; }
|
||||
|
||||
public StaticTile[][][] Tiles{ get; private set; }
|
||||
|
||||
public MultiTileEntry[] List{ get; private set; }
|
||||
|
||||
public void Add(int itemID, int x, int y, int z)
|
||||
{
|
||||
int vx = x + Center.m_X;
|
||||
int vy = y + Center.m_Y;
|
||||
|
||||
if (vx >= 0 && vx < Width && vy >= 0 && vy < Height)
|
||||
{
|
||||
StaticTile[] oldTiles = 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 = Tiles[vx][vy];
|
||||
|
||||
StaticTile[] 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);
|
||||
|
||||
Tiles[vx][vy] = newTiles;
|
||||
|
||||
MultiTileEntry[] oldList = List;
|
||||
MultiTileEntry[] 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, 1);
|
||||
|
||||
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 + Center.m_X;
|
||||
int vy = y + Center.m_Y;
|
||||
|
||||
if (vx >= 0 && vx < Width && vy >= 0 && vy < Height)
|
||||
{
|
||||
StaticTile[] oldTiles = Tiles[vx][vy];
|
||||
|
||||
for (int i = 0; i < oldTiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = oldTiles[i];
|
||||
|
||||
if (tile.Z == z && tile.Height >= minHeight)
|
||||
{
|
||||
StaticTile[] 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];
|
||||
|
||||
Tiles[vx][vy] = newTiles;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MultiTileEntry[] oldList = 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)
|
||||
{
|
||||
MultiTileEntry[] 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];
|
||||
|
||||
List = newList;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Remove(int itemID, int x, int y, int z)
|
||||
{
|
||||
int vx = x + Center.m_X;
|
||||
int vy = y + Center.m_Y;
|
||||
|
||||
if (vx >= 0 && vx < Width && vy >= 0 && vy < Height)
|
||||
{
|
||||
StaticTile[] oldTiles = Tiles[vx][vy];
|
||||
|
||||
for (int i = 0; i < oldTiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = oldTiles[i];
|
||||
|
||||
if (tile.ID == itemID && tile.Z == z)
|
||||
{
|
||||
StaticTile[] 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];
|
||||
|
||||
Tiles[vx][vy] = newTiles;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
MultiTileEntry[] oldList = 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)
|
||||
{
|
||||
MultiTileEntry[] 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];
|
||||
|
||||
List = newList;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Resize(int newWidth, int newHeight)
|
||||
{
|
||||
int oldWidth = Width, oldHeight = Height;
|
||||
StaticTile[][][] oldTiles = Tiles;
|
||||
|
||||
int totalLength = 0;
|
||||
|
||||
StaticTile[][][] 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;
|
||||
}
|
||||
}
|
||||
|
||||
Tiles = newTiles;
|
||||
List = new MultiTileEntry[totalLength];
|
||||
Width = newWidth;
|
||||
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)
|
||||
{
|
||||
StaticTile[] tiles = newTiles[x][y];
|
||||
|
||||
for (int i = 0; i < tiles.Length; ++i)
|
||||
{
|
||||
StaticTile tile = tiles[i];
|
||||
|
||||
int vx = x - Center.X;
|
||||
int vy = y - 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;
|
||||
|
||||
List[index++] = new MultiTileEntry((ushort)tile.ID, (short)vx, (short)vy, (short)tile.Z, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Serialize(GenericWriter writer)
|
||||
{
|
||||
writer.Write(1); // version;
|
||||
|
||||
writer.Write(m_Min);
|
||||
writer.Write(m_Max);
|
||||
writer.Write(Center);
|
||||
|
||||
writer.Write(Width);
|
||||
writer.Write(Height);
|
||||
|
||||
writer.Write(List.Length);
|
||||
|
||||
for (int i = 0; i < List.Length; ++i)
|
||||
{
|
||||
MultiTileEntry ent = List[i];
|
||||
|
||||
writer.Write(ent.m_ItemID);
|
||||
writer.Write(ent.m_OffsetX);
|
||||
writer.Write(ent.m_OffsetY);
|
||||
writer.Write(ent.m_OffsetZ);
|
||||
writer.Write(ent.m_Flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
82
Projects/Server/NativeReader.cs
Normal file
82
Projects/Server/NativeReader.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* NativeReader.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
|
||||
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
|
||||
{
|
||||
public unsafe void Read(IntPtr ptr, void* buffer, int length)
|
||||
{
|
||||
uint lpNumberOfBytesRead = 0;
|
||||
UnsafeNativeMethods.ReadFile(ptr, buffer, (uint)length, ref lpNumberOfBytesRead, null);
|
||||
}
|
||||
|
||||
internal static 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 sealed class NativeReaderUnix : INativeReader
|
||||
{
|
||||
public unsafe void Read(IntPtr ptr, void* buffer, int length)
|
||||
{
|
||||
UnsafeNativeMethods.read(ptr, buffer, length);
|
||||
}
|
||||
|
||||
internal static class UnsafeNativeMethods
|
||||
{
|
||||
[DllImport("libc")]
|
||||
internal static extern unsafe int read(IntPtr ptr, void* buffer, int length);
|
||||
}
|
||||
}
|
||||
}
|
||||
398
Projects/Server/Network/Compression.cs
Normal file
398
Projects/Server/Network/Compression.cs
Normal file
|
|
@ -0,0 +1,398 @@
|
|||
/***************************************************************************
|
||||
* Compression.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Handles outgoing packet compression for the network.
|
||||
/// </summary>
|
||||
public static class Compression
|
||||
{
|
||||
private const int CountIndex = 0;
|
||||
private const int ValueIndex = 1;
|
||||
|
||||
// UO packets may not exceed 64kb in length
|
||||
private const int BufferSize = 0x10000;
|
||||
|
||||
// Optimal compression ratio is 2 / 8; worst compression ratio is 11 / 8
|
||||
private const int MinimalCodeLength = 2;
|
||||
private const int MaximalCodeLength = 11;
|
||||
|
||||
// Fixed overhead, in bits, per compression call
|
||||
private const int TerminalCodeLength = 4;
|
||||
|
||||
// If our input exceeds this length, we cannot possibly compress it within the buffer
|
||||
private const int DefiniteOverflow = (BufferSize * 8 - TerminalCodeLength) / MinimalCodeLength;
|
||||
|
||||
// If our input exceeds this length, we may potentially overflow the buffer
|
||||
private const int PossibleOverflow = (BufferSize * 8 - TerminalCodeLength) / MaximalCodeLength;
|
||||
|
||||
private static int[] _huffmanTable = {
|
||||
0x2, 0x000, 0x5, 0x01F, 0x6, 0x022, 0x7, 0x034, 0x7, 0x075, 0x6, 0x028, 0x6, 0x03B, 0x7, 0x032,
|
||||
0x8, 0x0E0, 0x8, 0x062, 0x7, 0x056, 0x8, 0x079, 0x9, 0x19D, 0x8, 0x097, 0x6, 0x02A, 0x7, 0x057,
|
||||
0x8, 0x071, 0x8, 0x05B, 0x9, 0x1CC, 0x8, 0x0A7, 0x7, 0x025, 0x7, 0x04F, 0x8, 0x066, 0x8, 0x07D,
|
||||
0x9, 0x191, 0x9, 0x1CE, 0x7, 0x03F, 0x9, 0x090, 0x8, 0x059, 0x8, 0x07B, 0x8, 0x091, 0x8, 0x0C6,
|
||||
0x6, 0x02D, 0x9, 0x186, 0x8, 0x06F, 0x9, 0x093, 0xA, 0x1CC, 0x8, 0x05A, 0xA, 0x1AE, 0xA, 0x1C0,
|
||||
0x9, 0x148, 0x9, 0x14A, 0x9, 0x082, 0xA, 0x19F, 0x9, 0x171, 0x9, 0x120, 0x9, 0x0E7, 0xA, 0x1F3,
|
||||
0x9, 0x14B, 0x9, 0x100, 0x9, 0x190, 0x6, 0x013, 0x9, 0x161, 0x9, 0x125, 0x9, 0x133, 0x9, 0x195,
|
||||
0x9, 0x173, 0x9, 0x1CA, 0x9, 0x086, 0x9, 0x1E9, 0x9, 0x0DB, 0x9, 0x1EC, 0x9, 0x08B, 0x9, 0x085,
|
||||
0x5, 0x00A, 0x8, 0x096, 0x8, 0x09C, 0x9, 0x1C3, 0x9, 0x19C, 0x9, 0x08F, 0x9, 0x18F, 0x9, 0x091,
|
||||
0x9, 0x087, 0x9, 0x0C6, 0x9, 0x177, 0x9, 0x089, 0x9, 0x0D6, 0x9, 0x08C, 0x9, 0x1EE, 0x9, 0x1EB,
|
||||
0x9, 0x084, 0x9, 0x164, 0x9, 0x175, 0x9, 0x1CD, 0x8, 0x05E, 0x9, 0x088, 0x9, 0x12B, 0x9, 0x172,
|
||||
0x9, 0x10A, 0x9, 0x08D, 0x9, 0x13A, 0x9, 0x11C, 0xA, 0x1E1, 0xA, 0x1E0, 0x9, 0x187, 0xA, 0x1DC,
|
||||
0xA, 0x1DF, 0x7, 0x074, 0x9, 0x19F, 0x8, 0x08D, 0x8, 0x0E4, 0x7, 0x079, 0x9, 0x0EA, 0x9, 0x0E1,
|
||||
0x8, 0x040, 0x7, 0x041, 0x9, 0x10B, 0x9, 0x0B0, 0x8, 0x06A, 0x8, 0x0C1, 0x7, 0x071, 0x7, 0x078,
|
||||
0x8, 0x0B1, 0x9, 0x14C, 0x7, 0x043, 0x8, 0x076, 0x7, 0x066, 0x7, 0x04D, 0x9, 0x08A, 0x6, 0x02F,
|
||||
0x8, 0x0C9, 0x9, 0x0CE, 0x9, 0x149, 0x9, 0x160, 0xA, 0x1BA, 0xA, 0x19E, 0xA, 0x39F, 0x9, 0x0E5,
|
||||
0x9, 0x194, 0x9, 0x184, 0x9, 0x126, 0x7, 0x030, 0x8, 0x06C, 0x9, 0x121, 0x9, 0x1E8, 0xA, 0x1C1,
|
||||
0xA, 0x11D, 0xA, 0x163, 0xA, 0x385, 0xA, 0x3DB, 0xA, 0x17D, 0xA, 0x106, 0xA, 0x397, 0xA, 0x24E,
|
||||
0x7, 0x02E, 0x8, 0x098, 0xA, 0x33C, 0xA, 0x32E, 0xA, 0x1E9, 0x9, 0x0BF, 0xA, 0x3DF, 0xA, 0x1DD,
|
||||
0xA, 0x32D, 0xA, 0x2ED, 0xA, 0x30B, 0xA, 0x107, 0xA, 0x2E8, 0xA, 0x3DE, 0xA, 0x125, 0xA, 0x1E8,
|
||||
0x9, 0x0E9, 0xA, 0x1CD, 0xA, 0x1B5, 0x9, 0x165, 0xA, 0x232, 0xA, 0x2E1, 0xB, 0x3AE, 0xB, 0x3C6,
|
||||
0xB, 0x3E2, 0xA, 0x205, 0xA, 0x29A, 0xA, 0x248, 0xA, 0x2CD, 0xA, 0x23B, 0xB, 0x3C5, 0xA, 0x251,
|
||||
0xA, 0x2E9, 0xA, 0x252, 0x9, 0x1EA, 0xB, 0x3A0, 0xB, 0x391, 0xA, 0x23C, 0xB, 0x392, 0xB, 0x3D5,
|
||||
0xA, 0x233, 0xA, 0x2CC, 0xB, 0x390, 0xA, 0x1BB, 0xB, 0x3A1, 0xB, 0x3C4, 0xA, 0x211, 0xA, 0x203,
|
||||
0x9, 0x12A, 0xA, 0x231, 0xB, 0x3E0, 0xA, 0x29B, 0xB, 0x3D7, 0xA, 0x202, 0xB, 0x3AD, 0xA, 0x213,
|
||||
0xA, 0x253, 0xA, 0x32C, 0xA, 0x23D, 0xA, 0x23F, 0xA, 0x32F, 0xA, 0x11C, 0xA, 0x384, 0xA, 0x31C,
|
||||
0xA, 0x17C, 0xA, 0x30A, 0xA, 0x2E0, 0xA, 0x276, 0xA, 0x250, 0xB, 0x3E3, 0xA, 0x396, 0xA, 0x18F,
|
||||
0xA, 0x204, 0xA, 0x206, 0xA, 0x230, 0xA, 0x265, 0xA, 0x212, 0xA, 0x23E, 0xB, 0x3AC, 0xB, 0x393,
|
||||
0xB, 0x3E1, 0xA, 0x1DE, 0xB, 0x3D6, 0xA, 0x31D, 0xB, 0x3E5, 0xB, 0x3E4, 0xA, 0x207, 0xB, 0x3C7,
|
||||
0xA, 0x277, 0xB, 0x3D4, 0x8, 0x0C0, 0xA, 0x162, 0xA, 0x3DA, 0xA, 0x124, 0xA, 0x1B4, 0xA, 0x264,
|
||||
0xA, 0x33D, 0xA, 0x1D1, 0xA, 0x1AF, 0xA, 0x39E, 0xA, 0x24F, 0xB, 0x373, 0xA, 0x249, 0xB, 0x372,
|
||||
0x9, 0x167, 0xA, 0x210, 0xA, 0x23A, 0xA, 0x1B8, 0xB, 0x3AF, 0xA, 0x18E, 0xA, 0x2EC, 0x7, 0x062,
|
||||
0x4, 0x00D
|
||||
};
|
||||
|
||||
public static readonly ICompressor Compressor;
|
||||
|
||||
static Compression()
|
||||
{
|
||||
if (Core.Unix)
|
||||
{
|
||||
if (Core.Is64Bit)
|
||||
Compressor = new CompressorUnix64();
|
||||
else
|
||||
Compressor = new CompressorUnix32();
|
||||
}
|
||||
else if (Core.Is64Bit)
|
||||
{
|
||||
Compressor = new Compressor64();
|
||||
}
|
||||
else
|
||||
{
|
||||
Compressor = new Compressor32();
|
||||
}
|
||||
}
|
||||
|
||||
public static unsafe void Compress(byte[] input, int offset, int count, byte[] output, ref int length)
|
||||
{
|
||||
if (input == null) throw new ArgumentNullException(nameof(input));
|
||||
|
||||
if (offset < 0 || offset >= input.Length) throw new ArgumentOutOfRangeException(nameof(offset));
|
||||
if (count < 0 || count > input.Length) throw new ArgumentOutOfRangeException(nameof(count));
|
||||
if (input.Length - offset < count) throw new ArgumentException();
|
||||
|
||||
length = 0;
|
||||
|
||||
if (count > DefiniteOverflow) return;
|
||||
|
||||
int bitCount = 0;
|
||||
int bitValue = 0;
|
||||
|
||||
fixed (int* pTable = _huffmanTable)
|
||||
{
|
||||
int* pEntry;
|
||||
|
||||
fixed (byte* pInputBuffer = input)
|
||||
{
|
||||
byte* pInput = pInputBuffer + offset, pInputEnd = pInput + count;
|
||||
|
||||
fixed (byte* pOutputBuffer = output)
|
||||
{
|
||||
byte* pOutput = pOutputBuffer, pOutputEnd = pOutput + BufferSize;
|
||||
|
||||
while (pInput < pInputEnd)
|
||||
{
|
||||
pEntry = &pTable[*pInput++ << 1];
|
||||
|
||||
bitCount += pEntry[CountIndex];
|
||||
|
||||
bitValue <<= pEntry[CountIndex];
|
||||
bitValue |= pEntry[ValueIndex];
|
||||
|
||||
while (bitCount >= 8)
|
||||
{
|
||||
bitCount -= 8;
|
||||
|
||||
if (pOutput < pOutputEnd)
|
||||
{
|
||||
*pOutput++ = (byte)(bitValue >> bitCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// terminal code
|
||||
pEntry = &pTable[0x200];
|
||||
|
||||
bitCount += pEntry[CountIndex];
|
||||
|
||||
bitValue <<= pEntry[CountIndex];
|
||||
bitValue |= pEntry[ValueIndex];
|
||||
|
||||
// align on byte boundary
|
||||
if ((bitCount & 7) != 0)
|
||||
{
|
||||
bitValue <<= 8 - (bitCount & 7);
|
||||
bitCount += 8 - (bitCount & 7);
|
||||
}
|
||||
|
||||
while (bitCount >= 8)
|
||||
{
|
||||
bitCount -= 8;
|
||||
|
||||
if (pOutput < pOutputEnd)
|
||||
{
|
||||
*pOutput++ = (byte)(bitValue >> bitCount);
|
||||
}
|
||||
else
|
||||
{
|
||||
length = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
length = (int)(pOutput - pOutputBuffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static ZLibError Pack(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return Compressor.Compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public static ZLibError Pack(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return Compressor.Compress(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public static ZLibError Unpack(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return Compressor.Decompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
}
|
||||
|
||||
public interface ICompressor
|
||||
{
|
||||
string Version{ get; }
|
||||
|
||||
ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality);
|
||||
|
||||
ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
}
|
||||
|
||||
public sealed class Compressor32 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("zlib32")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("zlib32")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Compressor64 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("zlib64")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("zlib64")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix32 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.compress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
return SafeNativeMethods.compress2(dest, ref destLength, source, sourceLength, quality);
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
return SafeNativeMethods.uncompress(dest, ref destLength, source, sourceLength);
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref int destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref int destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref int destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class CompressorUnix64 : ICompressor
|
||||
{
|
||||
public string Version => SafeNativeMethods.zlibVersion();
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Compress(byte[] dest, ref int destLength, byte[] source, int sourceLength, ZLibQuality quality)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.compress2(dest, ref destLengthLong, source, sourceLength, quality);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
public ZLibError Decompress(byte[] dest, ref int destLength, byte[] source, int sourceLength)
|
||||
{
|
||||
ulong destLengthLong = (ulong)destLength;
|
||||
ZLibError z = SafeNativeMethods.uncompress(dest, ref destLengthLong, source, sourceLength);
|
||||
destLength = (int)destLengthLong;
|
||||
return z;
|
||||
}
|
||||
|
||||
internal class SafeNativeMethods
|
||||
{
|
||||
[DllImport("libz")]
|
||||
internal static extern string zlibVersion();
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress(byte[] dest, ref ulong destLength, byte[] source, int sourceLength);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError compress2(byte[] dest, ref ulong destLength, byte[] source, int sourceLength,
|
||||
ZLibQuality quality);
|
||||
|
||||
[DllImport("libz")]
|
||||
internal static extern ZLibError uncompress(byte[] dest, ref ulong destLen, byte[] source, int sourceLen);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ZLibError
|
||||
{
|
||||
VersionError = -6,
|
||||
BufferError = -5,
|
||||
MemoryError = -4,
|
||||
DataError = -3,
|
||||
StreamError = -2,
|
||||
FileError = -1,
|
||||
|
||||
Okay = 0,
|
||||
|
||||
StreamEnd = 1,
|
||||
NeedDictionary = 2
|
||||
}
|
||||
|
||||
public enum ZLibQuality
|
||||
{
|
||||
Default = -1,
|
||||
|
||||
None = 0,
|
||||
|
||||
Speed = 1,
|
||||
Size = 9
|
||||
}
|
||||
}
|
||||
40
Projects/Server/Network/EncodedPacketHandler.cs
Normal file
40
Projects/Server/Network/EncodedPacketHandler.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
/***************************************************************************
|
||||
* EncodedPacketHandler.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public delegate void OnEncodedPacketReceive(NetState state, IEntity ent, EncodedReader pvSrc);
|
||||
|
||||
public class EncodedPacketHandler
|
||||
{
|
||||
public EncodedPacketHandler(int packetID, bool ingame, OnEncodedPacketReceive onReceive)
|
||||
{
|
||||
PacketID = packetID;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int PacketID{ get; }
|
||||
|
||||
public OnEncodedPacketReceive OnReceive{ get; }
|
||||
|
||||
public bool Ingame{ get; }
|
||||
}
|
||||
}
|
||||
48
Projects/Server/Network/EncodedReader.cs
Normal file
48
Projects/Server/Network/EncodedReader.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/***************************************************************************
|
||||
* EncodedReader.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public ref struct EncodedReader
|
||||
{
|
||||
private PacketReader m_Reader;
|
||||
|
||||
public EncodedReader(PacketReader reader)
|
||||
{
|
||||
m_Reader = reader;
|
||||
}
|
||||
|
||||
public void Trace(NetState state)
|
||||
{
|
||||
m_Reader.Trace(state);
|
||||
}
|
||||
|
||||
public int ReadInt32() => m_Reader.ReadByte() != 0 ? 0 : m_Reader.ReadInt32();
|
||||
|
||||
public Point3D ReadPoint3D() => m_Reader.ReadByte() != 3 ? Point3D.Zero :
|
||||
new Point3D(m_Reader.ReadInt16(), m_Reader.ReadInt16(), m_Reader.ReadByte());
|
||||
|
||||
public string ReadUnicodeStringSafe() => m_Reader.ReadByte() != 2 ? string.Empty :
|
||||
m_Reader.ReadUnicodeStringSafe(m_Reader.ReadUInt16());
|
||||
|
||||
public string ReadUnicodeString() => m_Reader.ReadByte() != 2 ? string.Empty :
|
||||
m_Reader.ReadUnicodeString(m_Reader.ReadUInt16());
|
||||
}
|
||||
}
|
||||
175
Projects/Server/Network/Listener.cs
Normal file
175
Projects/Server/Network/Listener.cs
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/***************************************************************************
|
||||
* Listener.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class Listener
|
||||
{
|
||||
private Socket m_Socket;
|
||||
private IPEndPoint m_EndPoint;
|
||||
public Listener(IPEndPoint ipep)
|
||||
{
|
||||
#pragma warning disable IDE0068 // Use recommended dispose pattern
|
||||
m_Socket = new Socket(ipep.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
|
||||
#pragma warning restore IDE0068 // Use recommended dispose pattern
|
||||
|
||||
m_Socket.LingerState.Enabled = false;
|
||||
m_Socket.ExclusiveAddressUse = false;
|
||||
m_EndPoint = ipep;
|
||||
}
|
||||
|
||||
public virtual async Task Start(MessagePump pump)
|
||||
{
|
||||
try
|
||||
{
|
||||
m_Socket.Bind(m_EndPoint);
|
||||
m_Socket.Listen(8);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
if (e is SocketException se)
|
||||
{
|
||||
if (se.ErrorCode == 10048)
|
||||
{
|
||||
// WSAEADDRINUSE
|
||||
Console.WriteLine("Listener Failed: {0}:{1} (In Use)", m_EndPoint.Address, m_EndPoint.Port);
|
||||
}
|
||||
else if (se.ErrorCode == 10049)
|
||||
{
|
||||
// WSAEADDRNOTAVAIL
|
||||
Console.WriteLine("Listener Failed: {0}:{1} (Unavailable)", m_EndPoint.Address, m_EndPoint.Port);
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Listener Exception:");
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
m_Socket = null;
|
||||
return;
|
||||
}
|
||||
|
||||
DisplayListener();
|
||||
|
||||
while (true)
|
||||
{
|
||||
Socket s;
|
||||
try
|
||||
{
|
||||
s = await m_Socket.AcceptAsync().ConfigureAwait(false);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (VerifySocket(s))
|
||||
_ = new NetState(s, pump);
|
||||
else
|
||||
Release(s);
|
||||
}
|
||||
}
|
||||
|
||||
private void DisplayListener()
|
||||
{
|
||||
if (!(m_Socket.LocalEndPoint is IPEndPoint ipep))
|
||||
return;
|
||||
|
||||
if (ipep.Address.Equals(IPAddress.Any) || ipep.Address.Equals(IPAddress.IPv6Any))
|
||||
{
|
||||
NetworkInterface[] adapters = NetworkInterface.GetAllNetworkInterfaces();
|
||||
foreach (NetworkInterface adapter in adapters)
|
||||
{
|
||||
IPInterfaceProperties properties = adapter.GetIPProperties();
|
||||
foreach (UnicastIPAddressInformation unicast in properties.UnicastAddresses)
|
||||
if (ipep.AddressFamily == unicast.Address.AddressFamily)
|
||||
Console.WriteLine("Listening: {0}:{1}", unicast.Address, ipep.Port);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("Listening: {0}:{1}", ipep.Address, ipep.Port);
|
||||
}
|
||||
}
|
||||
|
||||
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 Release(Socket socket)
|
||||
{
|
||||
try
|
||||
{
|
||||
socket.Shutdown(SocketShutdown.Both);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
socket.Close();
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
socket.Dispose();
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
NetState.TraceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Interlocked.Exchange<Socket>(ref m_Socket, null)?.Close();
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
77
Projects/Server/Network/MessagePump.cs
Normal file
77
Projects/Server/Network/MessagePump.cs
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
|
||||
/***************************************************************************
|
||||
* MessagePump.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Net;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class MessagePump
|
||||
{
|
||||
private ConcurrentQueue<Work> m_WorkQueue = new ConcurrentQueue<Work>();
|
||||
public Listener[] Listeners => new Listener[0];
|
||||
|
||||
public void AddListener(IPEndPoint ipep)
|
||||
{
|
||||
Listener[] listeners = new Listener[Listeners.Length + 1];
|
||||
Array.Copy(Listeners, listeners, Listeners.Length);
|
||||
Listener listener = new Listener(ipep);
|
||||
_ = listener.Start(this);
|
||||
listeners[Listeners.Length] = listener;
|
||||
}
|
||||
|
||||
public void QueueWork(NetState ns, in ReadOnlySequence<byte> seq, OnPacketReceive onReceive)
|
||||
{
|
||||
m_WorkQueue.Enqueue(new Work(ns, seq, onReceive));
|
||||
Core.Set();
|
||||
}
|
||||
|
||||
public void DoWork()
|
||||
{
|
||||
int count = m_WorkQueue.Count;
|
||||
while (count-- > 0)
|
||||
{
|
||||
if (!m_WorkQueue.TryDequeue(out Work work))
|
||||
break;
|
||||
|
||||
work.OnReceive(work.State, new PacketReader(work.Sequence));
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Optimize this with a pool
|
||||
private class Work
|
||||
{
|
||||
public NetState State;
|
||||
public ReadOnlySequence<byte> Sequence;
|
||||
public OnPacketReceive OnReceive;
|
||||
|
||||
public Work(NetState ns, in ReadOnlySequence<byte> seq, OnPacketReceive onReceive)
|
||||
{
|
||||
State = ns;
|
||||
Sequence = seq;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
764
Projects/Server/Network/NetState.cs
Normal file
764
Projects/Server/Network/NetState.cs
Normal file
|
|
@ -0,0 +1,764 @@
|
|||
/***************************************************************************
|
||||
* NetState.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Pipelines;
|
||||
using System.Net;
|
||||
using System.Net.Sockets;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Accounting;
|
||||
using Server.Diagnostics;
|
||||
using Server.Gumps;
|
||||
using Server.HuePickers;
|
||||
using Server.Items;
|
||||
using Server.Menus;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public interface IPacketEncoder
|
||||
{
|
||||
void EncodeOutgoingPacket(NetState to, ref Memory<byte> seq);
|
||||
void DecodeIncomingPacket(NetState from, ref Memory<byte> seq);
|
||||
}
|
||||
|
||||
public delegate void NetStateCreatedCallback(NetState ns);
|
||||
|
||||
[Flags]
|
||||
public enum ProtocolChanges
|
||||
{
|
||||
NewSpellbook = 0x00000001,
|
||||
DamagePacket = 0x00000002,
|
||||
Unpack = 0x00000004,
|
||||
BuffIcon = 0x00000008,
|
||||
NewHaven = 0x00000010,
|
||||
ContainerGridLines = 0x00000020,
|
||||
ExtendedSupportedFeatures = 0x00000040,
|
||||
StygianAbyss = 0x00000080,
|
||||
HighSeas = 0x00000100,
|
||||
NewCharacterList = 0x00000200,
|
||||
NewCharacterCreation = 0x00000400,
|
||||
ExtendedStatus = 0x00000800,
|
||||
NewMobileIncoming = 0x00001000,
|
||||
NewSecureTrading = 0x00002000,
|
||||
UltimaStore = 0x00004000,
|
||||
EndlessJourney = 0x00008000,
|
||||
|
||||
Version400a = NewSpellbook,
|
||||
Version407a = Version400a | DamagePacket,
|
||||
Version500a = Version407a | Unpack,
|
||||
Version502b = Version500a | BuffIcon,
|
||||
Version6000 = Version502b | NewHaven,
|
||||
Version6017 = Version6000 | ContainerGridLines,
|
||||
Version60142 = Version6017 | ExtendedSupportedFeatures,
|
||||
Version7000 = Version60142 | StygianAbyss,
|
||||
Version7090 = Version7000 | HighSeas,
|
||||
Version70130 = Version7090 | NewCharacterList,
|
||||
Version70160 = Version70130 | NewCharacterCreation,
|
||||
Version70300 = Version70160 | ExtendedStatus,
|
||||
Version70331 = Version70300 | NewMobileIncoming,
|
||||
Version704565 = Version70331 | NewSecureTrading,
|
||||
Version70500 = Version704565 | UltimaStore,
|
||||
Version70610 = Version70500 | EndlessJourney
|
||||
}
|
||||
|
||||
public class AsyncState
|
||||
{
|
||||
public bool Paused { get; set; }
|
||||
public AsyncState(bool paused)
|
||||
{
|
||||
Paused = paused;
|
||||
}
|
||||
}
|
||||
|
||||
public class NetState : IComparable<NetState>
|
||||
{
|
||||
private string m_ToString;
|
||||
private ClientVersion m_Version;
|
||||
private SendQueue<Packet> m_SendQueue = new SendQueue<Packet>();
|
||||
|
||||
public DateTime ConnectedOn { get; }
|
||||
|
||||
public TimeSpan ConnectedFor => DateTime.UtcNow - ConnectedOn;
|
||||
|
||||
public DateTime ThrottledUntil { get; set; }
|
||||
|
||||
internal int m_Seed;
|
||||
internal int m_AuthID;
|
||||
|
||||
public IPAddress Address { get; }
|
||||
|
||||
private static AsyncState m_PauseState = new AsyncState(true);
|
||||
private static AsyncState m_ResumeState = new AsyncState(false);
|
||||
|
||||
private static AsyncState m_AsyncState = m_ResumeState;
|
||||
|
||||
public IPacketEncoder PacketEncoder { get; set; }
|
||||
|
||||
public static NetStateCreatedCallback CreatedCallback { get; set; }
|
||||
|
||||
public bool SentFirstPacket { get; set; }
|
||||
|
||||
public bool BlockAllPackets { get; set; }
|
||||
|
||||
public ClientFlags Flags { get; set; }
|
||||
|
||||
public ClientVersion Version
|
||||
{
|
||||
get => m_Version;
|
||||
set
|
||||
{
|
||||
m_Version = value;
|
||||
|
||||
if (value >= m_Version70610)
|
||||
ProtocolChanges = ProtocolChanges.Version70610;
|
||||
if (value >= m_Version70500)
|
||||
ProtocolChanges = ProtocolChanges.Version70500;
|
||||
if (value >= m_Version704565)
|
||||
ProtocolChanges = ProtocolChanges.Version704565;
|
||||
else if (value >= m_Version70331)
|
||||
ProtocolChanges = ProtocolChanges.Version70331;
|
||||
else if (value >= m_Version70300)
|
||||
ProtocolChanges = ProtocolChanges.Version70300;
|
||||
else if (value >= m_Version70160)
|
||||
ProtocolChanges = ProtocolChanges.Version70160;
|
||||
else if (value >= m_Version70130)
|
||||
ProtocolChanges = ProtocolChanges.Version70130;
|
||||
else if (value >= m_Version7090)
|
||||
ProtocolChanges = ProtocolChanges.Version7090;
|
||||
else if (value >= m_Version7000)
|
||||
ProtocolChanges = ProtocolChanges.Version7000;
|
||||
else if (value >= m_Version60142)
|
||||
ProtocolChanges = ProtocolChanges.Version60142;
|
||||
else if (value >= m_Version6017)
|
||||
ProtocolChanges = ProtocolChanges.Version6017;
|
||||
else if (value >= m_Version6000)
|
||||
ProtocolChanges = ProtocolChanges.Version6000;
|
||||
else if (value >= m_Version502b)
|
||||
ProtocolChanges = ProtocolChanges.Version502b;
|
||||
else if (value >= m_Version500a)
|
||||
ProtocolChanges = ProtocolChanges.Version500a;
|
||||
else if (value >= m_Version407a)
|
||||
ProtocolChanges = ProtocolChanges.Version407a;
|
||||
else if (value >= m_Version400a) ProtocolChanges = ProtocolChanges.Version400a;
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly ClientVersion m_Version400a = new ClientVersion("4.0.0a");
|
||||
private static readonly ClientVersion m_Version407a = new ClientVersion("4.0.7a");
|
||||
private static readonly ClientVersion m_Version500a = new ClientVersion("5.0.0a");
|
||||
private static readonly ClientVersion m_Version502b = new ClientVersion("5.0.2b");
|
||||
private static readonly ClientVersion m_Version6000 = new ClientVersion("6.0.0.0");
|
||||
private static readonly ClientVersion m_Version6017 = new ClientVersion("6.0.1.7");
|
||||
private static readonly ClientVersion m_Version60142 = new ClientVersion("6.0.14.2");
|
||||
private static readonly ClientVersion m_Version7000 = new ClientVersion("7.0.0.0");
|
||||
private static readonly ClientVersion m_Version7090 = new ClientVersion("7.0.9.0");
|
||||
private static readonly ClientVersion m_Version70130 = new ClientVersion("7.0.13.0");
|
||||
private static readonly ClientVersion m_Version70160 = new ClientVersion("7.0.16.0");
|
||||
private static readonly ClientVersion m_Version70300 = new ClientVersion("7.0.30.0");
|
||||
private static readonly ClientVersion m_Version70331 = new ClientVersion("7.0.33.1");
|
||||
private static readonly ClientVersion m_Version704565 = new ClientVersion("7.0.45.65");
|
||||
private static readonly ClientVersion m_Version70500 = new ClientVersion("7.0.50.0");
|
||||
private static readonly ClientVersion m_Version70610 = new ClientVersion("7.0.61.0");
|
||||
|
||||
public bool NewSpellbook => (ProtocolChanges & ProtocolChanges.NewSpellbook) != 0;
|
||||
public bool DamagePacket => (ProtocolChanges & ProtocolChanges.DamagePacket) != 0;
|
||||
public bool Unpack => (ProtocolChanges & ProtocolChanges.Unpack) != 0;
|
||||
public bool BuffIcon => (ProtocolChanges & ProtocolChanges.BuffIcon) != 0;
|
||||
public bool NewHaven => (ProtocolChanges & ProtocolChanges.NewHaven) != 0;
|
||||
public bool ContainerGridLines => (ProtocolChanges & ProtocolChanges.ContainerGridLines) != 0;
|
||||
public bool ExtendedSupportedFeatures => (ProtocolChanges & ProtocolChanges.ExtendedSupportedFeatures) != 0;
|
||||
public bool StygianAbyss => (ProtocolChanges & ProtocolChanges.StygianAbyss) != 0;
|
||||
public bool HighSeas => (ProtocolChanges & ProtocolChanges.HighSeas) != 0;
|
||||
public bool NewCharacterList => (ProtocolChanges & ProtocolChanges.NewCharacterList) != 0;
|
||||
public bool NewCharacterCreation => (ProtocolChanges & ProtocolChanges.NewCharacterCreation) != 0;
|
||||
public bool ExtendedStatus => (ProtocolChanges & ProtocolChanges.ExtendedStatus) != 0;
|
||||
public bool NewMobileIncoming => (ProtocolChanges & ProtocolChanges.NewMobileIncoming) != 0;
|
||||
public bool NewSecureTrading => (ProtocolChanges & ProtocolChanges.NewSecureTrading) != 0;
|
||||
|
||||
public bool IsUOTDClient =>
|
||||
(Flags & ClientFlags.UOTD) != 0 || m_Version?.Type == ClientType.UOTD;
|
||||
|
||||
public bool IsSAClient => m_Version?.Type == ClientType.SA;
|
||||
|
||||
public List<SecureTrade> Trades { get; }
|
||||
|
||||
public void ValidateAllTrades()
|
||||
{
|
||||
for (int i = Trades.Count - 1; i >= 0; --i)
|
||||
{
|
||||
if (i >= Trades.Count) continue;
|
||||
|
||||
SecureTrade trade = Trades[i];
|
||||
|
||||
if (trade.From.Mobile.Deleted || trade.To.Mobile.Deleted || !trade.From.Mobile.Alive ||
|
||||
!trade.To.Mobile.Alive || !trade.From.Mobile.InRange(trade.To.Mobile, 2) ||
|
||||
trade.From.Mobile.Map != trade.To.Mobile.Map) trade.Cancel();
|
||||
}
|
||||
}
|
||||
|
||||
public void CancelAllTrades()
|
||||
{
|
||||
for (int i = Trades.Count - 1; i >= 0; --i)
|
||||
if (i < Trades.Count)
|
||||
Trades[i].Cancel();
|
||||
}
|
||||
|
||||
public void RemoveTrade(SecureTrade trade)
|
||||
{
|
||||
Trades.Remove(trade);
|
||||
}
|
||||
|
||||
public SecureTrade FindTrade(Mobile m)
|
||||
{
|
||||
for (int i = 0; i < Trades.Count; ++i)
|
||||
{
|
||||
SecureTrade trade = Trades[i];
|
||||
|
||||
if (trade.From.Mobile == m || trade.To.Mobile == m) return trade;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SecureTradeContainer FindTradeContainer(Mobile m)
|
||||
{
|
||||
for (int i = 0; i < Trades.Count; ++i)
|
||||
{
|
||||
SecureTrade trade = Trades[i];
|
||||
|
||||
SecureTradeInfo from = trade.From;
|
||||
SecureTradeInfo to = trade.To;
|
||||
|
||||
if (from.Mobile == Mobile && to.Mobile == m) return from.Container;
|
||||
|
||||
if (from.Mobile == m && to.Mobile == Mobile) return to.Container;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public SecureTradeContainer AddTrade(NetState state)
|
||||
{
|
||||
SecureTrade newTrade = new SecureTrade(Mobile, state.Mobile);
|
||||
|
||||
Trades.Add(newTrade);
|
||||
state.Trades.Add(newTrade);
|
||||
|
||||
return newTrade.From.Container;
|
||||
}
|
||||
|
||||
public bool Running { get; private set; }
|
||||
|
||||
public bool Seeded { get; set; }
|
||||
|
||||
public Socket Socket { get; private set; }
|
||||
|
||||
public bool CompressionEnabled { get; set; }
|
||||
|
||||
public int Sequence { get; set; }
|
||||
|
||||
public List<Gump> Gumps { get; private set; }
|
||||
|
||||
public List<HuePicker> HuePickers { get; private set; }
|
||||
|
||||
public List<IMenu> Menus { get; private set; }
|
||||
|
||||
public static int GumpCap { get; set; } = 512;
|
||||
|
||||
public static int HuePickerCap { get; set; } = 512;
|
||||
|
||||
public static int MenuCap { get; set; } = 512;
|
||||
|
||||
public void WriteConsole(string text)
|
||||
{
|
||||
Console.WriteLine("Client: {0}: {1}", this, text);
|
||||
}
|
||||
|
||||
public void WriteConsole(string format, params object[] args)
|
||||
{
|
||||
WriteConsole(string.Format(format, args));
|
||||
}
|
||||
|
||||
public void AddMenu(IMenu menu)
|
||||
{
|
||||
if (Menus == null)
|
||||
Menus = new List<IMenu>();
|
||||
|
||||
if (Menus.Count < MenuCap)
|
||||
Menus.Add(menu);
|
||||
else
|
||||
{
|
||||
WriteConsole("Exceeded menu cap, disconnecting...");
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveMenu(IMenu menu)
|
||||
{
|
||||
Menus?.Remove(menu);
|
||||
}
|
||||
|
||||
public void RemoveMenu(int index)
|
||||
{
|
||||
Menus?.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void ClearMenus()
|
||||
{
|
||||
Menus?.Clear();
|
||||
}
|
||||
|
||||
public void AddHuePicker(HuePicker huePicker)
|
||||
{
|
||||
if (HuePickers == null)
|
||||
HuePickers = new List<HuePicker>();
|
||||
|
||||
if (HuePickers.Count < HuePickerCap)
|
||||
HuePickers.Add(huePicker);
|
||||
else
|
||||
{
|
||||
WriteConsole("Exceeded hue picker cap, disconnecting...");
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveHuePicker(HuePicker huePicker)
|
||||
{
|
||||
HuePickers?.Remove(huePicker);
|
||||
}
|
||||
|
||||
public void RemoveHuePicker(int index)
|
||||
{
|
||||
HuePickers?.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void ClearHuePickers()
|
||||
{
|
||||
HuePickers?.Clear();
|
||||
}
|
||||
|
||||
public void AddGump(Gump gump)
|
||||
{
|
||||
if (Gumps == null)
|
||||
Gumps = new List<Gump>();
|
||||
|
||||
if (Gumps.Count < GumpCap)
|
||||
Gumps.Add(gump);
|
||||
else
|
||||
{
|
||||
WriteConsole("Exceeded gump cap, disconnecting...");
|
||||
Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveGump(Gump gump)
|
||||
{
|
||||
Gumps?.Remove(gump);
|
||||
}
|
||||
|
||||
public void RemoveGump(int index)
|
||||
{
|
||||
Gumps?.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void ClearGumps()
|
||||
{
|
||||
Gumps?.Clear();
|
||||
}
|
||||
|
||||
public void LaunchBrowser(string url)
|
||||
{
|
||||
Send(new MessageLocalized(Serial.MinusOne, -1, MessageType.Label, 0x35, 3, 501231, "", ""));
|
||||
Send(new LaunchBrowser(url));
|
||||
}
|
||||
|
||||
public CityInfo[] CityInfo { get; set; }
|
||||
|
||||
public Mobile Mobile { get; set; }
|
||||
|
||||
public ServerInfo[] ServerInfo { get; set; }
|
||||
|
||||
public IAccount Account { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return m_ToString;
|
||||
}
|
||||
|
||||
public static List<NetState> Instances { get; } = new List<NetState>();
|
||||
|
||||
public NetState(Socket socket, MessagePump pump)
|
||||
{
|
||||
Socket = socket;
|
||||
Seeded = false;
|
||||
Running = false;
|
||||
Gumps = new List<Gump>();
|
||||
HuePickers = new List<HuePicker>();
|
||||
Menus = new List<IMenu>();
|
||||
Trades = new List<SecureTrade>();
|
||||
|
||||
m_NextCheckActivity = Core.TickCount + 30000;
|
||||
|
||||
Instances.Add(this);
|
||||
|
||||
try
|
||||
{
|
||||
Address = Utility.Intern(((IPEndPoint)Socket.RemoteEndPoint).Address);
|
||||
m_ToString = Address.ToString();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TraceException(ex);
|
||||
Address = IPAddress.None;
|
||||
m_ToString = "(error)";
|
||||
}
|
||||
|
||||
ConnectedOn = DateTime.UtcNow;
|
||||
_ = Start(pump);
|
||||
|
||||
CreatedCallback?.Invoke(this);
|
||||
Console.WriteLine("Client: {0}: Connected. [{1} Online]", this, NetState.Instances.Count);
|
||||
}
|
||||
|
||||
public static void Pause()
|
||||
{
|
||||
m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_PauseState);
|
||||
}
|
||||
|
||||
public static void Resume()
|
||||
{
|
||||
m_AsyncState = Interlocked.Exchange(ref m_AsyncState, m_ResumeState);
|
||||
}
|
||||
|
||||
public virtual void Send(Packet p)
|
||||
{
|
||||
if (Socket == null || BlockAllPackets)
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
m_SendQueue.Enqueue(p);
|
||||
}
|
||||
|
||||
public bool CheckEncrypted(int packetID)
|
||||
{
|
||||
if (!SentFirstPacket && packetID != 0xF0 && packetID != 0xF1 && packetID != 0xCF && packetID != 0x80 &&
|
||||
packetID != 0x91 && packetID != 0xA4 && packetID != 0xEF)
|
||||
{
|
||||
Console.WriteLine("Client: {0}: Encrypted client detected, disconnecting", this);
|
||||
Dispose();
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Pipe m_RecvdPipe;
|
||||
|
||||
private async Task Start(MessagePump pump)
|
||||
{
|
||||
m_RecvdPipe = new Pipe();
|
||||
Running = true;
|
||||
|
||||
await Task.WhenAll(ProcessSends(), ProcessRecvs(), HandlePackets(pump)).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
private async Task ProcessRecvs()
|
||||
{
|
||||
PipeWriter w = m_RecvdPipe.Writer;
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (m_AsyncState.Paused)
|
||||
{
|
||||
await Timer.Pause(50).ConfigureAwait(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
Memory<byte> memory = w.GetMemory();
|
||||
int bytesRead = await Socket.ReceiveAsync(memory, SocketFlags.None).ConfigureAwait(false);
|
||||
if (bytesRead == 0)
|
||||
break;
|
||||
|
||||
Interlocked.Exchange(ref m_NextCheckActivity, Core.TickCount + 90000);
|
||||
|
||||
w.Advance(bytesRead);
|
||||
|
||||
FlushResult result = await w.FlushAsync().ConfigureAwait(false);
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
break;
|
||||
}
|
||||
catch
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
w.Complete();
|
||||
Dispose();
|
||||
}
|
||||
|
||||
private async Task ProcessSends()
|
||||
{
|
||||
while (true)
|
||||
{
|
||||
try
|
||||
{
|
||||
Packet p = await m_SendQueue?.DequeueAsync() ?? null;
|
||||
if (p == null)
|
||||
break;
|
||||
|
||||
ReadOnlyMemory<byte> buffer = p.Compile(CompressionEnabled, out int length);
|
||||
|
||||
if (buffer.Length <= 0 || length <= 0)
|
||||
{
|
||||
p.OnSend();
|
||||
return;
|
||||
}
|
||||
|
||||
buffer = buffer.Slice(0, length);
|
||||
|
||||
PacketSendProfile prof = null;
|
||||
|
||||
if (Core.Profiling)
|
||||
prof = PacketSendProfile.Acquire(p.GetType());
|
||||
|
||||
prof?.Start();
|
||||
|
||||
await Socket.SendAsync(buffer, SocketFlags.None).ConfigureAwait(false);
|
||||
|
||||
p.OnSend();
|
||||
|
||||
prof?.Finish(length);
|
||||
}
|
||||
catch (SocketException ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
TraceException(ex);
|
||||
Dispose();
|
||||
break;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async Task HandlePackets(MessagePump pump)
|
||||
{
|
||||
PipeReader pr = m_RecvdPipe.Reader;
|
||||
|
||||
while (true)
|
||||
{
|
||||
ReadResult result = await pr.ReadAsync();
|
||||
ReadOnlySequence<byte> seq = result.Buffer;
|
||||
if (seq.Length == 0)
|
||||
break;
|
||||
|
||||
long pos = PacketHandlers.ProcessPacket(pump, this, seq);
|
||||
|
||||
if (pos <= 0)
|
||||
break;
|
||||
|
||||
pr.AdvanceTo(seq.GetPosition(pos, seq.Start));
|
||||
|
||||
if (result.IsCompleted || result.IsCanceled)
|
||||
break;
|
||||
}
|
||||
|
||||
pr.Complete();
|
||||
}
|
||||
|
||||
public PacketHandler GetHandler(int packetID)
|
||||
{
|
||||
return ContainerGridLines ? PacketHandlers.Get6017Handler(packetID) :
|
||||
PacketHandlers.GetHandler(packetID);
|
||||
}
|
||||
|
||||
private long m_NextCheckActivity;
|
||||
|
||||
public void CheckAlive(long curTicks)
|
||||
{
|
||||
if (Socket == null || m_NextCheckActivity - curTicks >= 0)
|
||||
return;
|
||||
|
||||
Console.WriteLine("Client: {0}: Disconnecting due to inactivity...", this);
|
||||
Dispose();
|
||||
}
|
||||
|
||||
public static void TraceException(Exception ex)
|
||||
{
|
||||
if (!Core.Debug)
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("network-errors.log", true))
|
||||
{
|
||||
op.WriteLine("# {0}", DateTime.UtcNow);
|
||||
|
||||
op.WriteLine(ex);
|
||||
|
||||
op.WriteLine();
|
||||
op.WriteLine();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
|
||||
private int m_Disposing;
|
||||
|
||||
public bool IsDisposing { get { return m_Disposing != 0; } private set { m_Disposing = value ? 1 : 0; } }
|
||||
|
||||
public virtual void Dispose()
|
||||
{
|
||||
int disposing = Interlocked.Exchange(ref m_Disposing, 1);
|
||||
if (disposing == 1)
|
||||
return;
|
||||
|
||||
Task.Run(async () =>
|
||||
{
|
||||
m_RecvdPipe.Reader.CancelPendingRead();
|
||||
m_RecvdPipe.Reader.Complete();
|
||||
await m_RecvdPipe.Writer.FlushAsync().ConfigureAwait(false);
|
||||
m_RecvdPipe.Writer.Complete();
|
||||
|
||||
try { Socket.Shutdown(SocketShutdown.Both); } catch (Exception ex) { TraceException(ex); }
|
||||
try { Socket.Close(); } catch (Exception ex) { TraceException(ex); }
|
||||
|
||||
Socket = null;
|
||||
m_RecvdPipe = null;
|
||||
m_SendQueue = null;
|
||||
m_Disposed.Enqueue(this);
|
||||
});
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
Timer.DelayCall(TimeSpan.FromMinutes(1.0), TimeSpan.FromMinutes(1.5), CheckAllAlive);
|
||||
}
|
||||
|
||||
public static void CheckAllAlive()
|
||||
{
|
||||
try
|
||||
{
|
||||
long curTicks = Core.TickCount;
|
||||
|
||||
if (Instances.Count >= 1024)
|
||||
Parallel.ForEach(Instances, ns => ns.CheckAlive(curTicks));
|
||||
else
|
||||
for (int i = 0; i < Instances.Count; ++i)
|
||||
Instances[i].CheckAlive(curTicks);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
TraceException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static ConcurrentQueue<NetState> m_Disposed = new ConcurrentQueue<NetState>();
|
||||
|
||||
public static void ProcessDisposedQueue()
|
||||
{
|
||||
int breakout = 0;
|
||||
|
||||
while (breakout++ < 200)
|
||||
{
|
||||
if (!m_Disposed.TryDequeue(out NetState ns))
|
||||
break;
|
||||
|
||||
Mobile m = ns.Mobile;
|
||||
IAccount a = ns.Account;
|
||||
|
||||
if (m != null)
|
||||
{
|
||||
m.NetState = null;
|
||||
ns.Mobile = null;
|
||||
}
|
||||
|
||||
ns.Gumps.Clear();
|
||||
ns.Menus.Clear();
|
||||
ns.HuePickers.Clear();
|
||||
ns.Account = null;
|
||||
ns.ServerInfo = null;
|
||||
ns.CityInfo = null;
|
||||
|
||||
Instances.Remove(ns);
|
||||
|
||||
if (a != null)
|
||||
ns.WriteConsole("Disconnected. [{0} Online] [{1}]", Instances.Count, a);
|
||||
else
|
||||
ns.WriteConsole("Disconnected. [{0} Online]", Instances.Count);
|
||||
}
|
||||
}
|
||||
|
||||
public ExpansionInfo ExpansionInfo
|
||||
{
|
||||
get
|
||||
{
|
||||
for (int i = ExpansionInfo.Table.Length - 1; i >= 0; i--)
|
||||
{
|
||||
ExpansionInfo info = ExpansionInfo.Table[i];
|
||||
|
||||
if (info.RequiredClient != null && Version >= info.RequiredClient || (Flags & info.ClientFlags) != 0)
|
||||
return info;
|
||||
}
|
||||
|
||||
return ExpansionInfo.GetInfo(Expansion.None);
|
||||
}
|
||||
}
|
||||
|
||||
public Expansion Expansion => (Expansion)ExpansionInfo.ID;
|
||||
|
||||
public ProtocolChanges ProtocolChanges { get; set; }
|
||||
|
||||
public bool SupportsExpansion(ExpansionInfo info, bool checkCoreExpansion = true)
|
||||
{
|
||||
if (info == null || checkCoreExpansion && (int)Core.Expansion < info.ID)
|
||||
return false;
|
||||
|
||||
return info.RequiredClient != null ? Version >= info.RequiredClient : (Flags & info.ClientFlags) != 0;
|
||||
}
|
||||
|
||||
public bool SupportsExpansion(Expansion ex, bool checkCoreExpansion = true)
|
||||
{
|
||||
return SupportsExpansion(ExpansionInfo.GetInfo(ex), checkCoreExpansion);
|
||||
}
|
||||
|
||||
public int CompareTo(NetState other)
|
||||
{
|
||||
return other == null ? 1 : m_ToString.CompareTo(other.m_ToString);
|
||||
}
|
||||
}
|
||||
}
|
||||
273
Projects/Server/Network/Packet.cs
Normal file
273
Projects/Server/Network/Packet.cs
Normal file
|
|
@ -0,0 +1,273 @@
|
|||
/***************************************************************************
|
||||
* Packet.cs
|
||||
* -------------------
|
||||
* begin : August 2, 2019
|
||||
* 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 Server.Diagnostics;
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public abstract class Packet
|
||||
{
|
||||
private const int CompressorBufferSize = 0x10000;
|
||||
|
||||
private const int BufferSize = 4096;
|
||||
|
||||
private byte[] m_CompiledBuffer;
|
||||
private int m_CompiledLength;
|
||||
private int m_Length;
|
||||
private State m_State;
|
||||
|
||||
protected PacketWriter m_Stream;
|
||||
|
||||
protected Packet(int packetID)
|
||||
{
|
||||
PacketID = packetID;
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
PacketSendProfile prof = PacketSendProfile.Acquire(GetType());
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
protected Packet(int packetID, int length)
|
||||
{
|
||||
PacketID = packetID;
|
||||
m_Length = length;
|
||||
|
||||
m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
m_Stream.Write((byte)packetID);
|
||||
|
||||
if (Core.Profiling)
|
||||
{
|
||||
PacketSendProfile prof = PacketSendProfile.Acquire(GetType());
|
||||
prof.Increment();
|
||||
}
|
||||
}
|
||||
|
||||
public int PacketID { get; }
|
||||
|
||||
public PacketWriter UnderlyingStream => m_Stream;
|
||||
|
||||
public void EnsureCapacity(int length)
|
||||
{
|
||||
m_Stream = PacketWriter.CreateInstance(length); // new PacketWriter( length );
|
||||
m_Stream.Write((byte)PacketID);
|
||||
m_Stream.Write((short)0);
|
||||
}
|
||||
|
||||
public static Packet SetStatic(Packet p)
|
||||
{
|
||||
p.SetStatic();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static Packet Acquire(Packet p)
|
||||
{
|
||||
p.Acquire();
|
||||
return p;
|
||||
}
|
||||
|
||||
public static void Release(ref Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
p = null;
|
||||
}
|
||||
|
||||
public static void Release(Packet p)
|
||||
{
|
||||
p?.Release();
|
||||
}
|
||||
|
||||
public void SetStatic()
|
||||
{
|
||||
m_State |= State.Static | State.Acquired;
|
||||
}
|
||||
|
||||
public void Acquire()
|
||||
{
|
||||
m_State |= State.Acquired;
|
||||
}
|
||||
|
||||
public void OnSend()
|
||||
{
|
||||
Core.Set(); // Is this still needed if this is done async?
|
||||
|
||||
if ((m_State & (State.Acquired | State.Static)) == 0)
|
||||
Free();
|
||||
}
|
||||
|
||||
private void Free()
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
return;
|
||||
|
||||
if ((m_State & State.Buffered) != 0)
|
||||
ArrayPool<byte>.Shared.Return(m_CompiledBuffer);
|
||||
|
||||
m_State &= ~(State.Static | State.Acquired | State.Buffered);
|
||||
|
||||
m_CompiledBuffer = null;
|
||||
}
|
||||
|
||||
public void Release()
|
||||
{
|
||||
if ((m_State & State.Acquired) != 0)
|
||||
Free();
|
||||
}
|
||||
|
||||
public byte[] Compile(bool compress, out int length)
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (m_CompiledBuffer == null)
|
||||
{
|
||||
if ((m_State & State.Accessed) == 0)
|
||||
{
|
||||
m_State |= State.Accessed;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((m_State & State.Warned) == 0)
|
||||
{
|
||||
m_State |= State.Warned;
|
||||
|
||||
try
|
||||
{
|
||||
using (StreamWriter op = new StreamWriter("net_opt.log", true))
|
||||
{
|
||||
op.WriteLine("Redundant compile for packet {0}, use Acquire() and Release()", GetType());
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
m_CompiledBuffer = new byte[0];
|
||||
m_CompiledLength = 0;
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
|
||||
InternalCompile(compress);
|
||||
}
|
||||
|
||||
length = m_CompiledLength;
|
||||
return m_CompiledBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
private void InternalCompile(bool compress)
|
||||
{
|
||||
if (m_Length == 0)
|
||||
{
|
||||
long streamLen = m_Stream.Length;
|
||||
|
||||
m_Stream.Seek(1, SeekOrigin.Begin);
|
||||
m_Stream.Write((ushort)streamLen);
|
||||
}
|
||||
else if (m_Stream.Length != m_Length)
|
||||
{
|
||||
int diff = (int)m_Stream.Length - m_Length;
|
||||
|
||||
Console.WriteLine("Packet: 0x{0:X2}: Bad packet length! ({1}{2} bytes)", PacketID, diff >= 0 ? "+" : "",
|
||||
diff);
|
||||
}
|
||||
|
||||
MemoryStream ms = m_Stream.UnderlyingStream;
|
||||
|
||||
m_CompiledBuffer = ms.GetBuffer();
|
||||
int length = (int)ms.Length;
|
||||
|
||||
if (compress)
|
||||
{
|
||||
byte[] buffer = ArrayPool<byte>.Shared.Rent(CompressorBufferSize);
|
||||
|
||||
Compression.Compress(m_CompiledBuffer, 0, length, buffer, ref length);
|
||||
|
||||
if (length <= 0)
|
||||
{
|
||||
Console.WriteLine("Warning: Compression buffer overflowed on packet 0x{0:X2} ('{1}') (length={2})",
|
||||
PacketID, GetType().Name, length);
|
||||
using (StreamWriter op = new StreamWriter("compression_overflow.log", true))
|
||||
{
|
||||
op.WriteLine("{0} Warning: Compression buffer overflowed on packet 0x{1:X2} ('{2}') (length={3})",
|
||||
DateTime.UtcNow, PacketID, GetType().Name, length);
|
||||
op.WriteLine(new StackTrace());
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledLength = length;
|
||||
|
||||
if ((m_State & State.Static) != 0)
|
||||
{
|
||||
m_CompiledBuffer = new byte[length];
|
||||
Buffer.BlockCopy(buffer, 0, m_CompiledBuffer, 0, length);
|
||||
ArrayPool<byte>.Shared.Return(buffer);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_CompiledBuffer = buffer;
|
||||
m_State |= State.Buffered;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (length > 0)
|
||||
{
|
||||
byte[] old = m_CompiledBuffer;
|
||||
m_CompiledLength = length;
|
||||
|
||||
if ((m_State & State.Static) != 0)
|
||||
m_CompiledBuffer = new byte[length];
|
||||
else
|
||||
{
|
||||
m_CompiledBuffer = ArrayPool<byte>.Shared.Rent(length);
|
||||
m_State |= State.Buffered;
|
||||
}
|
||||
|
||||
Buffer.BlockCopy(old, 0, m_CompiledBuffer, 0, length);
|
||||
}
|
||||
|
||||
PacketWriter.ReleaseInstance(m_Stream);
|
||||
m_Stream = null;
|
||||
}
|
||||
|
||||
[Flags]
|
||||
private enum State
|
||||
{
|
||||
Inactive = 0x00,
|
||||
Static = 0x01,
|
||||
Acquired = 0x02,
|
||||
Accessed = 0x04,
|
||||
Buffered = 0x08,
|
||||
Warned = 0x10
|
||||
}
|
||||
}
|
||||
}
|
||||
49
Projects/Server/Network/PacketHandler.cs
Normal file
49
Projects/Server/Network/PacketHandler.cs
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
/***************************************************************************
|
||||
* PacketHandler.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.Network
|
||||
{
|
||||
public delegate void OnPacketReceive(NetState state, PacketReader pvSrc);
|
||||
|
||||
public delegate TimeSpan ThrottlePacketCallback(NetState state);
|
||||
|
||||
public class PacketHandler
|
||||
{
|
||||
public PacketHandler(int packetID, long length, bool ingame, OnPacketReceive onReceive)
|
||||
{
|
||||
PacketID = packetID;
|
||||
Length = length;
|
||||
Ingame = ingame;
|
||||
OnReceive = onReceive;
|
||||
}
|
||||
|
||||
public int PacketID{ get; }
|
||||
|
||||
public long Length{ get; }
|
||||
|
||||
public OnPacketReceive OnReceive{ get; }
|
||||
|
||||
public ThrottlePacketCallback ThrottleCallback{ get; set; }
|
||||
|
||||
public bool Ingame{ get; }
|
||||
}
|
||||
}
|
||||
2799
Projects/Server/Network/PacketHandlers.cs
Normal file
2799
Projects/Server/Network/PacketHandlers.cs
Normal file
File diff suppressed because it is too large
Load diff
315
Projects/Server/Network/PacketReader.cs
Normal file
315
Projects/Server/Network/PacketReader.cs
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
/***************************************************************************
|
||||
* PacketReader.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.IO;
|
||||
using System.IO.Pipelines;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public ref struct PacketReader
|
||||
{
|
||||
private SequenceReader<byte> m_Reader;
|
||||
|
||||
public SequencePosition Position => m_Reader.Position;
|
||||
public long Length => m_Reader.Length;
|
||||
public long Consumed => m_Reader.Consumed;
|
||||
public long Remaining => m_Reader.Remaining;
|
||||
|
||||
public PacketReader(ReadOnlySequence<byte> seq)
|
||||
{
|
||||
m_Reader = new SequenceReader<byte>(seq);
|
||||
}
|
||||
|
||||
public byte Peek() => m_Reader.TryPeek(out byte value) ? value : (byte)0;
|
||||
|
||||
public void Trace(NetState state)
|
||||
{
|
||||
try
|
||||
{
|
||||
using (StreamWriter sw = new StreamWriter("Packets.log", true))
|
||||
{
|
||||
byte[] buffer = m_Reader.Sequence.ToArray();
|
||||
|
||||
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
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
public SequencePosition Seek(long offset, SeekOrigin origin)
|
||||
{
|
||||
switch (origin)
|
||||
{
|
||||
case SeekOrigin.Begin:
|
||||
if (offset < m_Reader.Consumed)
|
||||
m_Reader.Rewind(m_Reader.Consumed - Math.Max(offset, 0L));
|
||||
else
|
||||
m_Reader.Advance(offset - m_Reader.Consumed);
|
||||
break;
|
||||
case SeekOrigin.Current:
|
||||
if (offset < 0)
|
||||
m_Reader.Rewind(Math.Min(m_Reader.Consumed, offset * -1));
|
||||
else
|
||||
m_Reader.Advance(Math.Min(m_Reader.Remaining, offset));
|
||||
break;
|
||||
case SeekOrigin.End:
|
||||
long count = m_Reader.Remaining - offset;
|
||||
if (count < 0)
|
||||
m_Reader.Rewind(count * -1);
|
||||
else if (count > 0)
|
||||
m_Reader.Advance(count);
|
||||
break;
|
||||
}
|
||||
|
||||
return m_Reader.Position;
|
||||
}
|
||||
|
||||
public bool TryReadByte(out byte value) => m_Reader.TryRead(out value);
|
||||
|
||||
public int ReadInt32() => m_Reader.TryReadBigEndian(out int value) ? value : 0;
|
||||
|
||||
public short ReadInt16() => m_Reader.TryReadBigEndian(out short value) ? value : (short)0;
|
||||
|
||||
public byte ReadByte() => m_Reader.TryRead(out byte value) ? value : (byte)0;
|
||||
|
||||
public uint ReadUInt32() => (uint)ReadInt32();
|
||||
|
||||
public ushort ReadUInt16() => (ushort)ReadInt16();
|
||||
|
||||
public sbyte ReadSByte() => (sbyte)ReadByte();
|
||||
|
||||
public bool ReadBoolean() => ReadByte() > 0;
|
||||
|
||||
public string ReadUnicodeStringLE()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLE(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLESafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength * 2);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringLESafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadLittleEndian(out short c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public bool IsSafeChar(int c)
|
||||
{
|
||||
return c >= 0x20 && c < 0xFFFE;
|
||||
}
|
||||
|
||||
public string ReadUTF8StringSafe(int fixedLength)
|
||||
{
|
||||
string s;
|
||||
|
||||
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
|
||||
s = Utility.UTF8.GetString(span.Length > fixedLength ? span.Slice(0, fixedLength) : span);
|
||||
else
|
||||
{
|
||||
long size = Math.Min(m_Reader.Remaining, fixedLength);
|
||||
s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, size).ToArray());
|
||||
m_Reader.Advance(size);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
string s;
|
||||
|
||||
if (m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true))
|
||||
s = Utility.UTF8.GetString(span);
|
||||
else
|
||||
{
|
||||
s = Utility.UTF8.GetString(m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray());
|
||||
m_Reader.Advance(m_Reader.Remaining);
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
return Utility.UTF8.GetString(
|
||||
m_Reader.TryReadTo(out ReadOnlySpan<byte> span, (byte)'\0', true) ? span :
|
||||
m_Reader.Sequence.Slice(m_Reader.Position, m_Reader.Remaining).ToArray()
|
||||
);
|
||||
}
|
||||
|
||||
public string ReadString()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryRead(out byte c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe()
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (m_Reader.TryRead(out byte c))
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeStringSafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength * 2);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadUnicodeString(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryReadBigEndian(out short c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength * 2);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadStringSafe(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0)
|
||||
if (IsSafeChar(c))
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
|
||||
public string ReadString(int fixedLength)
|
||||
{
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
while (fixedLength-- > 0 && m_Reader.TryRead(out byte c) && c != 0)
|
||||
sb.Append((char)c);
|
||||
|
||||
if (fixedLength > 0)
|
||||
m_Reader.Advance(fixedLength);
|
||||
|
||||
return sb.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
346
Projects/Server/Network/PacketWriter.cs
Normal file
346
Projects/Server/Network/PacketWriter.cs
Normal file
|
|
@ -0,0 +1,346 @@
|
|||
/***************************************************************************
|
||||
* PacketWriter.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides functionality for writing primitive binary data.
|
||||
/// </summary>
|
||||
public class PacketWriter
|
||||
{
|
||||
private static ConcurrentQueue<PacketWriter> m_Pool = new ConcurrentQueue<PacketWriter>();
|
||||
|
||||
/// <summary>
|
||||
/// Internal format buffer.
|
||||
/// </summary>
|
||||
private byte[] m_Buffer = new byte[4];
|
||||
|
||||
private int m_Capacity;
|
||||
|
||||
/// <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 = 32)
|
||||
{
|
||||
UnderlyingStream = new MemoryStream(capacity);
|
||||
m_Capacity = capacity;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the total stream length.
|
||||
/// </summary>
|
||||
public long Length => UnderlyingStream.Length;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the current stream position.
|
||||
/// </summary>
|
||||
public long Position
|
||||
{
|
||||
get => UnderlyingStream.Position;
|
||||
set => UnderlyingStream.Position = value;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The internal stream used by this PacketWriter instance.
|
||||
/// </summary>
|
||||
public MemoryStream UnderlyingStream { get; private set; }
|
||||
|
||||
public static PacketWriter CreateInstance(int capacity = 32)
|
||||
{
|
||||
if (m_Pool.TryDequeue(out PacketWriter pw))
|
||||
{
|
||||
pw.m_Capacity = capacity;
|
||||
pw.UnderlyingStream.SetLength(0);
|
||||
return pw;
|
||||
}
|
||||
|
||||
return new PacketWriter(capacity);
|
||||
}
|
||||
|
||||
public static void ReleaseInstance(PacketWriter pw)
|
||||
{
|
||||
m_Pool.Enqueue(pw);
|
||||
}
|
||||
|
||||
/// <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)
|
||||
{
|
||||
UnderlyingStream.WriteByte((byte)(value ? 1 : 0));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte unsigned integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(byte value)
|
||||
{
|
||||
UnderlyingStream.WriteByte(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a 1-byte signed integer value to the underlying stream.
|
||||
/// </summary>
|
||||
public void Write(sbyte value)
|
||||
{
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.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)
|
||||
{
|
||||
UnderlyingStream.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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.ASCII.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length + 1);
|
||||
|
||||
Encoding.ASCII.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += length + 1;
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position += Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += 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;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size)
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.Unicode.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.Unicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <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;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + (length + 1) * 2);
|
||||
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += 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;
|
||||
}
|
||||
|
||||
int length = value.Length;
|
||||
size *= 2;
|
||||
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + size);
|
||||
|
||||
if (length * 2 >= size )
|
||||
{
|
||||
UnderlyingStream.Position +=
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, size, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
}
|
||||
else
|
||||
{
|
||||
Encoding.BigEndianUnicode.GetBytes(value, 0, length, UnderlyingStream.GetBuffer(), (int)UnderlyingStream.Position);
|
||||
UnderlyingStream.Position += size;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Fills the stream from the current position up to (capacity) with 0x00's
|
||||
/// </summary>
|
||||
public void Fill()
|
||||
{
|
||||
Fill(m_Capacity - UnderlyingStream.Length);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes a number of 0x00 byte values to the underlying stream.
|
||||
/// </summary>
|
||||
public void Fill(long length)
|
||||
{
|
||||
if (UnderlyingStream.Position == UnderlyingStream.Length)
|
||||
{
|
||||
UnderlyingStream.SetLength(UnderlyingStream.Length + length);
|
||||
UnderlyingStream.Seek(0, SeekOrigin.End);
|
||||
}
|
||||
else
|
||||
{
|
||||
UnderlyingStream.Write(new byte[length], 0, (int)length);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Offsets the current position from an origin.
|
||||
/// </summary>
|
||||
public long Seek(long offset, SeekOrigin origin) => UnderlyingStream.Seek(offset, origin);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the entire stream content as a byte array.
|
||||
/// </summary>
|
||||
public byte[] ToArray() => UnderlyingStream.ToArray();
|
||||
}
|
||||
}
|
||||
4277
Projects/Server/Network/Packets.cs
Normal file
4277
Projects/Server/Network/Packets.cs
Normal file
File diff suppressed because it is too large
Load diff
51
Projects/Server/Network/SendQueue.cs
Normal file
51
Projects/Server/Network/SendQueue.cs
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/***************************************************************************
|
||||
* SendQueue.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.Collections.Concurrent;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public class SendQueue<T>
|
||||
{
|
||||
private BlockingCollection<T> m_Queue = new BlockingCollection<T>(new ConcurrentQueue<T>());
|
||||
|
||||
public SendQueue()
|
||||
{
|
||||
}
|
||||
|
||||
public void Enqueue(T t)
|
||||
{
|
||||
m_Queue.Add(t);
|
||||
}
|
||||
|
||||
public Task<T> DequeueAsync()
|
||||
{
|
||||
TaskCompletionSource<T> taskCompletion = new TaskCompletionSource<T>();
|
||||
Task.Run(() => taskCompletion.SetResult(Dequeue()));
|
||||
return taskCompletion.Task;
|
||||
}
|
||||
|
||||
public T Dequeue()
|
||||
{
|
||||
return m_Queue.Take();
|
||||
}
|
||||
}
|
||||
}
|
||||
57
Projects/Server/Network/SocketExtensions.cs
Normal file
57
Projects/Server/Network/SocketExtensions.cs
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
/***************************************************************************
|
||||
* SocketExtensions.cs
|
||||
* -------------------
|
||||
* begin : August 2, 2019
|
||||
* copyright : (C) The ModernUO Team
|
||||
* email : hi@modernuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Net.Sockets;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class SocketExtensions
|
||||
{
|
||||
public static Task<int> ReceiveAsync(this Socket socket, Memory<byte> memory, SocketFlags socketFlags)
|
||||
{
|
||||
return SocketTaskExtensions.ReceiveAsync(socket, GetArray(memory), socketFlags);
|
||||
}
|
||||
|
||||
public static ArraySegment<byte> GetArray(this Memory<byte> memory)
|
||||
{
|
||||
return ((ReadOnlyMemory<byte>)memory).GetArray();
|
||||
}
|
||||
|
||||
public static ArraySegment<byte> GetArray(this ReadOnlyMemory<byte> memory)
|
||||
{
|
||||
if (MemoryMarshal.TryGetArray(memory, out var result))
|
||||
return result;
|
||||
|
||||
throw new InvalidOperationException("Buffer backed by array was expected");
|
||||
}
|
||||
|
||||
public static ArraySegment<byte> GetArray(this ReadOnlySequence<byte> memory)
|
||||
{
|
||||
if (SequenceMarshal.TryGetArray(memory, out var result))
|
||||
return result;
|
||||
|
||||
throw new InvalidOperationException("Buffer backed by array was expected");
|
||||
}
|
||||
}
|
||||
}
|
||||
135
Projects/Server/Network/StaticPacketHandlers.cs
Normal file
135
Projects/Server/Network/StaticPacketHandlers.cs
Normal file
|
|
@ -0,0 +1,135 @@
|
|||
/***************************************************************************
|
||||
* StaticPacketHandlers.cs
|
||||
* -------------------
|
||||
* begin : March 15, 2019
|
||||
* copyright : (C) The ModernUO Team
|
||||
* email : hi@modernuo.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.Collections.Concurrent;
|
||||
|
||||
namespace Server.Network
|
||||
{
|
||||
public static class StaticPacketHandlers
|
||||
{
|
||||
private static ConcurrentDictionary<IPropertyListObject,OPLInfo> OPLInfoPackets = new ConcurrentDictionary<IPropertyListObject,OPLInfo>();
|
||||
private static ConcurrentDictionary<IPropertyListObject,ObjectPropertyList> ObjectPropertyListPackets = new ConcurrentDictionary<IPropertyListObject,ObjectPropertyList>();
|
||||
private static ConcurrentDictionary<IEntity,RemoveEntity> RemoveEntityPackets = new ConcurrentDictionary<IEntity,RemoveEntity>();
|
||||
|
||||
private static ConcurrentDictionary<Item,WorldItem> WorldItemPackets = new ConcurrentDictionary<Item,WorldItem>();
|
||||
private static ConcurrentDictionary<Item,WorldItemSA> WorldItemSAPackets = new ConcurrentDictionary<Item,WorldItemSA>();
|
||||
private static ConcurrentDictionary<Item,WorldItemHS> WorldItemHSPackets = new ConcurrentDictionary<Item,WorldItemHS>();
|
||||
|
||||
public static OPLInfo GetOPLInfoPacket(IPropertyListObject obj)
|
||||
{
|
||||
return OPLInfoPackets.GetOrAdd(obj, value =>
|
||||
{
|
||||
OPLInfo packet = new OPLInfo(value.PropertyList);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static OPLInfo FreeOPLInfoPacket(IPropertyListObject obj)
|
||||
{
|
||||
if (OPLInfoPackets.TryRemove(obj, out OPLInfo p))
|
||||
Packet.Release(p);
|
||||
|
||||
return p;
|
||||
}
|
||||
|
||||
public static ObjectPropertyList GetOPLPacket(IPropertyListObject obj)
|
||||
{
|
||||
return ObjectPropertyListPackets.GetOrAdd(obj, value =>
|
||||
{
|
||||
ObjectPropertyList list = new ObjectPropertyList(value);
|
||||
|
||||
value.GetProperties(list);
|
||||
if (value is Item item)
|
||||
item.AppendChildProperties(list);
|
||||
|
||||
list.Terminate();
|
||||
list.SetStatic();
|
||||
return list;
|
||||
});
|
||||
}
|
||||
|
||||
public static ObjectPropertyList FreeOPLPacket(IPropertyListObject obj)
|
||||
{
|
||||
if (ObjectPropertyListPackets.TryRemove(obj, out ObjectPropertyList list))
|
||||
Packet.Release(list);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
public static RemoveEntity GetRemoveEntityPacket(IEntity entity)
|
||||
{
|
||||
return RemoveEntityPackets.GetOrAdd(entity, value =>
|
||||
{
|
||||
RemoveEntity packet = new RemoveEntity(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static void FreeRemoveItemPacket(IEntity entity)
|
||||
{
|
||||
if (RemoveEntityPackets.TryRemove(entity, out RemoveEntity p))
|
||||
Packet.Release(p);
|
||||
}
|
||||
|
||||
public static WorldItem GetWorldItemPacket(Item item)
|
||||
{
|
||||
return WorldItemPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItem packet = new WorldItem(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static WorldItemSA GetWorldItemSAPacket(Item item)
|
||||
{
|
||||
return WorldItemSAPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItemSA packet = new WorldItemSA(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static WorldItemHS GetWorldItemHSPacket(Item item)
|
||||
{
|
||||
return WorldItemHSPackets.GetOrAdd(item, value =>
|
||||
{
|
||||
WorldItemHS packet = new WorldItemHS(value);
|
||||
packet.SetStatic();
|
||||
return packet;
|
||||
});
|
||||
}
|
||||
|
||||
public static void FreeWorldItemPackets(Item item)
|
||||
{
|
||||
if (WorldItemPackets.TryRemove(item, out WorldItem wi))
|
||||
Packet.Release(wi);
|
||||
|
||||
if (WorldItemSAPackets.TryRemove(item, out WorldItemSA wisa))
|
||||
Packet.Release(wisa);
|
||||
|
||||
if (WorldItemHSPackets.TryRemove(item, out WorldItemHS wihs))
|
||||
Packet.Release(wihs);
|
||||
}
|
||||
}
|
||||
}
|
||||
62
Projects/Server/Notoriety.cs
Normal file
62
Projects/Server/Notoriety.cs
Normal file
|
|
@ -0,0 +1,62 @@
|
|||
/***************************************************************************
|
||||
* Notoriety.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public delegate int NotorietyHandler(Mobile source, Mobile target);
|
||||
|
||||
public static class Notoriety
|
||||
{
|
||||
public const int Innocent = 1;
|
||||
public const int Ally = 2;
|
||||
public const int CanBeAttacked = 3;
|
||||
public const int Criminal = 4;
|
||||
public const int Enemy = 5;
|
||||
public const int Murderer = 6;
|
||||
public const int Invulnerable = 7;
|
||||
|
||||
public static NotorietyHandler Handler{ get; set; }
|
||||
|
||||
public static int[] Hues{ get; set; } =
|
||||
{
|
||||
0x000,
|
||||
0x059,
|
||||
0x03F,
|
||||
0x3B2,
|
||||
0x3B2,
|
||||
0x090,
|
||||
0x022,
|
||||
0x035
|
||||
};
|
||||
|
||||
public static int GetHue(int noto)
|
||||
{
|
||||
if (noto < 0 || noto >= Hues.Length)
|
||||
return 0;
|
||||
|
||||
return Hues[noto];
|
||||
}
|
||||
|
||||
public static int Compute(Mobile source, Mobile target)
|
||||
{
|
||||
return Handler?.Invoke(source, target) ?? CanBeAttacked;
|
||||
}
|
||||
}
|
||||
}
|
||||
202
Projects/Server/ObjectPropertyList.cs
Normal file
202
Projects/Server/ObjectPropertyList.cs
Normal file
|
|
@ -0,0 +1,202 @@
|
|||
/***************************************************************************
|
||||
* ObjectPropertyList.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.IO;
|
||||
using System.Text;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public interface IPropertyListObject : IEntity
|
||||
{
|
||||
ObjectPropertyList PropertyList{ get; }
|
||||
OPLInfo OPLPacket{ get; }
|
||||
|
||||
void GetProperties(ObjectPropertyList list);
|
||||
}
|
||||
|
||||
public sealed class ObjectPropertyList : Packet
|
||||
{
|
||||
private static byte[] m_Buffer = new byte[1024];
|
||||
private static Encoding m_Encoding = Encoding.Unicode;
|
||||
|
||||
// Each of these are localized to "~1_NOTHING~" which allows the string argument to be used
|
||||
private static int[] m_StringNumbers =
|
||||
{
|
||||
1042971,
|
||||
1070722
|
||||
};
|
||||
|
||||
private int m_Hash;
|
||||
private int m_Strings;
|
||||
|
||||
public ObjectPropertyList(IEntity e) : base(0xD6)
|
||||
{
|
||||
EnsureCapacity(128);
|
||||
|
||||
Entity = e;
|
||||
|
||||
m_Stream.Write((short)1);
|
||||
m_Stream.Write(e.Serial);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write((byte)0);
|
||||
m_Stream.Write(e.Serial);
|
||||
}
|
||||
|
||||
public IEntity Entity{ get; }
|
||||
|
||||
public int Hash => 0x40000000 + m_Hash;
|
||||
|
||||
public int Header{ get; set; }
|
||||
|
||||
public string HeaderArgs{ get; set; }
|
||||
|
||||
public static bool Enabled{ get; set; }
|
||||
|
||||
public void Add(int number)
|
||||
{
|
||||
if (number == 0)
|
||||
return;
|
||||
|
||||
AddHash(number);
|
||||
|
||||
if (Header == 0)
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = "";
|
||||
}
|
||||
|
||||
m_Stream.Write(number);
|
||||
m_Stream.Write((short)0);
|
||||
}
|
||||
|
||||
public void Terminate()
|
||||
{
|
||||
m_Stream.Write(0);
|
||||
|
||||
m_Stream.Seek(11, SeekOrigin.Begin);
|
||||
m_Stream.Write(m_Hash);
|
||||
}
|
||||
|
||||
public void AddHash(int val)
|
||||
{
|
||||
m_Hash ^= val & 0x3FFFFFF;
|
||||
m_Hash ^= (val >> 26) & 0x3F;
|
||||
}
|
||||
|
||||
public void Add(int number, string arguments)
|
||||
{
|
||||
if (number == 0)
|
||||
return;
|
||||
|
||||
if (arguments == null)
|
||||
arguments = "";
|
||||
|
||||
if (Header == 0)
|
||||
{
|
||||
Header = number;
|
||||
HeaderArgs = arguments;
|
||||
}
|
||||
|
||||
AddHash(number);
|
||||
AddHash(arguments.GetHashCode());
|
||||
|
||||
m_Stream.Write(number);
|
||||
|
||||
int byteCount = m_Encoding.GetByteCount(arguments);
|
||||
|
||||
if (byteCount > m_Buffer.Length)
|
||||
m_Buffer = new byte[byteCount];
|
||||
|
||||
byteCount = m_Encoding.GetBytes(arguments, 0, arguments.Length, m_Buffer, 0);
|
||||
|
||||
m_Stream.Write((short)byteCount);
|
||||
m_Stream.Write(m_Buffer, 0, byteCount);
|
||||
}
|
||||
|
||||
public void Add(int number, string format, object arg0)
|
||||
{
|
||||
Add(number, string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public void Add(int number, string format, object arg0, object arg1)
|
||||
{
|
||||
Add(number, string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public void Add(int number, string format, object arg0, object arg1, object arg2)
|
||||
{
|
||||
Add(number, string.Format(format, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
public void Add(int number, string format, params object[] args)
|
||||
{
|
||||
Add(number, string.Format(format, args));
|
||||
}
|
||||
|
||||
private int GetStringNumber()
|
||||
{
|
||||
return m_StringNumbers[m_Strings++ % m_StringNumbers.Length];
|
||||
}
|
||||
|
||||
public void Add(string text)
|
||||
{
|
||||
Add(GetStringNumber(), text);
|
||||
}
|
||||
|
||||
public void Add(string format, string arg0)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0));
|
||||
}
|
||||
|
||||
public void Add(string format, string arg0, string arg1)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0, arg1));
|
||||
}
|
||||
|
||||
public void Add(string format, string arg0, string arg1, string arg2)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, arg0, arg1, arg2));
|
||||
}
|
||||
|
||||
public void Add(string format, params object[] args)
|
||||
{
|
||||
Add(GetStringNumber(), string.Format(format, args));
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class OPLInfo : Packet
|
||||
{
|
||||
/*public OPLInfo( ObjectPropertyList list ) : base( 0xBF )
|
||||
{
|
||||
EnsureCapacity( 13 );
|
||||
|
||||
m_Stream.Write( (short) 0x10 );
|
||||
m_Stream.Write( (int) list.Entity.Serial );
|
||||
m_Stream.Write( (int) list.Hash );
|
||||
}*/
|
||||
|
||||
public OPLInfo(ObjectPropertyList list) : base(0xDC, 9)
|
||||
{
|
||||
m_Stream.Write(list.Entity.Serial);
|
||||
m_Stream.Write(list.Hash);
|
||||
}
|
||||
}
|
||||
}
|
||||
35
Projects/Server/Party.cs
Normal file
35
Projects/Server/Party.cs
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
/***************************************************************************
|
||||
* Party.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class PartyCommands
|
||||
{
|
||||
public static PartyCommands Handler{ get; set; }
|
||||
|
||||
public abstract void OnAdd(Mobile from);
|
||||
public abstract void OnRemove(Mobile from, Mobile target);
|
||||
public abstract void OnPrivateMessage(Mobile from, Mobile target, string text);
|
||||
public abstract void OnPublicMessage(Mobile from, string text);
|
||||
public abstract void OnSetCanLoot(Mobile from, bool canLoot);
|
||||
public abstract void OnAccept(Mobile from, Mobile leader);
|
||||
public abstract void OnDecline(Mobile from, Mobile leader);
|
||||
}
|
||||
}
|
||||
82
Projects/Server/Persistence/BinaryMemoryWriter.cs
Normal file
82
Projects/Server/Persistence/BinaryMemoryWriter.cs
Normal file
|
|
@ -0,0 +1,82 @@
|
|||
/***************************************************************************
|
||||
* BinaryMemoryWriter.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.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class BinaryMemoryWriter : BinaryFileWriter
|
||||
{
|
||||
private static byte[] indexBuffer;
|
||||
private MemoryStream stream;
|
||||
|
||||
public BinaryMemoryWriter()
|
||||
: base(new MemoryStream(512), true)
|
||||
{
|
||||
stream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
|
||||
protected override int BufferSize => 512;
|
||||
|
||||
public int CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile, int typeCode, uint serial)
|
||||
{
|
||||
Flush();
|
||||
|
||||
byte[] buffer = stream.GetBuffer();
|
||||
int length = (int)stream.Length;
|
||||
|
||||
long position = dataFile.Position;
|
||||
|
||||
dataFile.Write(buffer, 0, length);
|
||||
|
||||
if (indexBuffer == null) indexBuffer = new byte[20];
|
||||
|
||||
indexBuffer[0] = (byte)typeCode;
|
||||
indexBuffer[1] = (byte)(typeCode >> 8);
|
||||
indexBuffer[2] = (byte)(typeCode >> 16);
|
||||
indexBuffer[3] = (byte)(typeCode >> 24);
|
||||
|
||||
indexBuffer[4] = (byte)serial;
|
||||
indexBuffer[5] = (byte)(serial >> 8);
|
||||
indexBuffer[6] = (byte)(serial >> 16);
|
||||
indexBuffer[7] = (byte)(serial >> 24);
|
||||
|
||||
indexBuffer[8] = (byte)position;
|
||||
indexBuffer[9] = (byte)(position >> 8);
|
||||
indexBuffer[10] = (byte)(position >> 16);
|
||||
indexBuffer[11] = (byte)(position >> 24);
|
||||
indexBuffer[12] = (byte)(position >> 32);
|
||||
indexBuffer[13] = (byte)(position >> 40);
|
||||
indexBuffer[14] = (byte)(position >> 48);
|
||||
indexBuffer[15] = (byte)(position >> 56);
|
||||
|
||||
indexBuffer[16] = (byte)length;
|
||||
indexBuffer[17] = (byte)(length >> 8);
|
||||
indexBuffer[18] = (byte)(length >> 16);
|
||||
indexBuffer[19] = (byte)(length >> 24);
|
||||
|
||||
indexFile.Write(indexBuffer, 0, indexBuffer.Length);
|
||||
|
||||
stream.SetLength(0);
|
||||
|
||||
return length;
|
||||
}
|
||||
}
|
||||
}
|
||||
48
Projects/Server/Persistence/DualSaveStrategy.cs
Normal file
48
Projects/Server/Persistence/DualSaveStrategy.cs
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
/***************************************************************************
|
||||
* DualSaveStrategy.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.Threading;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class DualSaveStrategy : StandardSaveStrategy
|
||||
{
|
||||
public override string Name => "Dual";
|
||||
|
||||
public override void Save(bool permitBackgroundWrite)
|
||||
{
|
||||
PermitBackgroundWrite = permitBackgroundWrite;
|
||||
|
||||
Thread saveThread = new Thread(delegate() { SaveItems(); });
|
||||
|
||||
saveThread.Name = "Item Save Subset";
|
||||
saveThread.Start();
|
||||
|
||||
SaveMobiles();
|
||||
SaveGuilds();
|
||||
|
||||
saveThread.Join();
|
||||
|
||||
if (permitBackgroundWrite && UseSequentialWriters
|
||||
) //If we're permitted to write in the background, but we don't anyways, then notify.
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
}
|
||||
}
|
||||
278
Projects/Server/Persistence/DynamicSaveStrategy.cs
Normal file
278
Projects/Server/Persistence/DynamicSaveStrategy.cs
Normal file
|
|
@ -0,0 +1,278 @@
|
|||
/***************************************************************************
|
||||
* DynamicSaveStrategy.cs
|
||||
* -------------------
|
||||
* begin : December 16, 2010
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Server.Guilds;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class DynamicSaveStrategy : SaveStrategy
|
||||
{
|
||||
private ConcurrentBag<Item> _decayBag;
|
||||
private SequentialFileWriter _guildData, _guildIndex;
|
||||
private BlockingCollection<QueuedMemoryWriter> _guildThreadWriters;
|
||||
|
||||
private SequentialFileWriter _itemData, _itemIndex;
|
||||
|
||||
private BlockingCollection<QueuedMemoryWriter> _itemThreadWriters;
|
||||
|
||||
private SequentialFileWriter _mobileData, _mobileIndex;
|
||||
private BlockingCollection<QueuedMemoryWriter> _mobileThreadWriters;
|
||||
|
||||
public DynamicSaveStrategy()
|
||||
{
|
||||
_decayBag = new ConcurrentBag<Item>();
|
||||
_itemThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_mobileThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
_guildThreadWriters = new BlockingCollection<QueuedMemoryWriter>();
|
||||
}
|
||||
|
||||
public override string Name => "Dynamic";
|
||||
|
||||
public override void Save(bool permitBackgroundWrite)
|
||||
{
|
||||
OpenFiles();
|
||||
|
||||
Task[] saveTasks = new Task[3];
|
||||
|
||||
saveTasks[0] = SaveItems();
|
||||
saveTasks[1] = SaveMobiles();
|
||||
saveTasks[2] = SaveGuilds();
|
||||
|
||||
SaveTypeDatabases();
|
||||
|
||||
if (permitBackgroundWrite)
|
||||
{
|
||||
//This option makes it finish the writing to disk in the background, continuing even after Save() returns.
|
||||
Task.Factory.ContinueWhenAll(saveTasks, _ =>
|
||||
{
|
||||
CloseFiles();
|
||||
|
||||
World.NotifyDiskWriteComplete();
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
Task.WaitAll(saveTasks); //Waits for the completion of all of the tasks(committing to disk)
|
||||
CloseFiles();
|
||||
}
|
||||
}
|
||||
|
||||
private Task StartCommitTask(BlockingCollection<QueuedMemoryWriter> threadWriter, SequentialFileWriter data,
|
||||
SequentialFileWriter index)
|
||||
{
|
||||
Task commitTask = Task.Factory.StartNew(() =>
|
||||
{
|
||||
while (!threadWriter.IsCompleted)
|
||||
{
|
||||
QueuedMemoryWriter writer;
|
||||
|
||||
try
|
||||
{
|
||||
writer = threadWriter.Take();
|
||||
}
|
||||
catch (InvalidOperationException)
|
||||
{
|
||||
//Per MSDN, it's fine if we're here, successful completion of adding can rarely put us into this state.
|
||||
break;
|
||||
}
|
||||
|
||||
writer.CommitTo(data, index);
|
||||
}
|
||||
});
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
private Task SaveItems()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_itemThreadWriters, _itemData, _itemIndex);
|
||||
|
||||
IEnumerable<Item> items = World.Items.Values;
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(items, () => new QueuedMemoryWriter(),
|
||||
(item, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
item.Serialize(writer);
|
||||
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
writer.QueueForIndex(item, size);
|
||||
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal &&
|
||||
DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayBag.Add(item);
|
||||
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_itemThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
_itemThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
private Task SaveMobiles()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_mobileThreadWriters, _mobileData, _mobileIndex);
|
||||
|
||||
IEnumerable<Mobile> mobiles = World.Mobiles.Values;
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(mobiles, () => new QueuedMemoryWriter(),
|
||||
(mobile, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
mobile.Serialize(writer);
|
||||
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
writer.QueueForIndex(mobile, size);
|
||||
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_mobileThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
_mobileThreadWriters
|
||||
.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task tell the consumer that we're done
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
private Task SaveGuilds()
|
||||
{
|
||||
//Start the blocking consumer; this runs in background.
|
||||
Task commitTask = StartCommitTask(_guildThreadWriters, _guildData, _guildIndex);
|
||||
|
||||
IEnumerable<BaseGuild> guilds = BaseGuild.List.Values;
|
||||
|
||||
//Start the producer.
|
||||
Parallel.ForEach(guilds, () => new QueuedMemoryWriter(),
|
||||
(guild, state, writer) =>
|
||||
{
|
||||
long startPosition = writer.Position;
|
||||
|
||||
guild.Serialize(writer);
|
||||
|
||||
int size = (int)(writer.Position - startPosition);
|
||||
|
||||
writer.QueueForIndex(guild, size);
|
||||
|
||||
return writer;
|
||||
},
|
||||
writer =>
|
||||
{
|
||||
writer.Flush();
|
||||
|
||||
_guildThreadWriters.Add(writer);
|
||||
});
|
||||
|
||||
_guildThreadWriters.CompleteAdding(); //We only get here after the Parallel.ForEach completes. Lets our task
|
||||
|
||||
return commitTask;
|
||||
}
|
||||
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
while (_decayBag.TryTake(out Item item))
|
||||
if (item.OnDecay())
|
||||
item.Delete();
|
||||
}
|
||||
|
||||
private void OpenFiles()
|
||||
{
|
||||
_itemData = new SequentialFileWriter(World.ItemDataPath);
|
||||
_itemIndex = new SequentialFileWriter(World.ItemIndexPath);
|
||||
|
||||
_mobileData = new SequentialFileWriter(World.MobileDataPath);
|
||||
_mobileIndex = new SequentialFileWriter(World.MobileIndexPath);
|
||||
|
||||
_guildData = new SequentialFileWriter(World.GuildDataPath);
|
||||
_guildIndex = new SequentialFileWriter(World.GuildIndexPath);
|
||||
|
||||
WriteCount(_itemIndex, World.Items.Count);
|
||||
WriteCount(_mobileIndex, World.Mobiles.Count);
|
||||
WriteCount(_guildIndex, BaseGuild.List.Count);
|
||||
}
|
||||
|
||||
private void CloseFiles()
|
||||
{
|
||||
_itemData.Close();
|
||||
_itemIndex.Close();
|
||||
|
||||
_mobileData.Close();
|
||||
_mobileIndex.Close();
|
||||
|
||||
_guildData.Close();
|
||||
_guildIndex.Close();
|
||||
}
|
||||
|
||||
private void WriteCount(SequentialFileWriter indexFile, int count)
|
||||
{
|
||||
//Equiv to GenericWriter.Write( (int)count );
|
||||
byte[] buffer = new byte[4];
|
||||
|
||||
buffer[0] = (byte)count;
|
||||
buffer[1] = (byte)(count >> 8);
|
||||
buffer[2] = (byte)(count >> 16);
|
||||
buffer[3] = (byte)(count >> 24);
|
||||
|
||||
indexFile.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private void SaveTypeDatabases()
|
||||
{
|
||||
SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes);
|
||||
SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes);
|
||||
}
|
||||
|
||||
private void SaveTypeDatabase(string path, List<Type> types)
|
||||
{
|
||||
BinaryFileWriter bfw = new BinaryFileWriter(path, false);
|
||||
|
||||
bfw.Write(types.Count);
|
||||
|
||||
foreach (Type type in types) bfw.Write(type.FullName);
|
||||
|
||||
bfw.Flush();
|
||||
|
||||
bfw.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
113
Projects/Server/Persistence/FileOperations.cs
Normal file
113
Projects/Server/Persistence/FileOperations.cs
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
/***************************************************************************
|
||||
* FileOperations.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
#if !MONO
|
||||
using System.Runtime.InteropServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
|
||||
#endif
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class FileOperations
|
||||
{
|
||||
public const int KB = 1024;
|
||||
public const int MB = 1024 * KB;
|
||||
|
||||
public static int BufferSize{ get; set; } = 1 * MB;
|
||||
|
||||
public static int Concurrency{ get; set; } = 1;
|
||||
|
||||
public static bool Unbuffered{ get; set; } = true;
|
||||
|
||||
public static bool AreSynchronous => Concurrency < 1;
|
||||
|
||||
public static bool AreAsynchronous => Concurrency > 0;
|
||||
|
||||
public static FileStream OpenSequentialStream(string path, FileMode mode, FileAccess access, FileShare share)
|
||||
{
|
||||
FileOptions options = FileOptions.SequentialScan;
|
||||
|
||||
if (Concurrency > 0)
|
||||
options |= FileOptions.Asynchronous;
|
||||
|
||||
#if MONO
|
||||
return new FileStream( path, mode, access, share, BufferSize, options );
|
||||
#else
|
||||
if (Unbuffered)
|
||||
options |= NoBuffering;
|
||||
else
|
||||
return new FileStream(path, mode, access, share, BufferSize, options);
|
||||
|
||||
SafeFileHandle fileHandle =
|
||||
UnsafeNativeMethods.CreateFile(path, (int)access, share, IntPtr.Zero, mode, (int)options, IntPtr.Zero);
|
||||
|
||||
if (fileHandle.IsInvalid) throw new IOException();
|
||||
|
||||
return new UnbufferedFileStream(fileHandle, access, BufferSize, Concurrency > 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if !MONO
|
||||
private class UnbufferedFileStream : FileStream
|
||||
{
|
||||
private SafeFileHandle fileHandle;
|
||||
|
||||
public UnbufferedFileStream(SafeFileHandle fileHandle, FileAccess access, int bufferSize, bool isAsync)
|
||||
: base(fileHandle, access, bufferSize, isAsync)
|
||||
{
|
||||
this.fileHandle = fileHandle;
|
||||
}
|
||||
|
||||
public override void Write(byte[] array, int offset, int count)
|
||||
{
|
||||
base.Write(array, offset, BufferSize);
|
||||
}
|
||||
|
||||
public override IAsyncResult BeginWrite(byte[] array, int offset, int numBytes, AsyncCallback userCallback,
|
||||
object stateObject)
|
||||
{
|
||||
return base.BeginWrite(array, offset, BufferSize, userCallback, stateObject);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!fileHandle.IsClosed) fileHandle.Close();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !MONO
|
||||
private const FileOptions NoBuffering = (FileOptions)0x20000000;
|
||||
|
||||
internal static class UnsafeNativeMethods
|
||||
{
|
||||
[DllImport("Kernel32", CharSet = CharSet.Unicode, SetLastError = true)]
|
||||
internal static extern SafeFileHandle CreateFile(string lpFileName, int dwDesiredAccess, FileShare dwShareMode,
|
||||
IntPtr securityAttrs, FileMode dwCreationDisposition, int dwFlagsAndAttributes, IntPtr hTemplateFile);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
231
Projects/Server/Persistence/FileQueue.cs
Normal file
231
Projects/Server/Persistence/FileQueue.cs
Normal file
|
|
@ -0,0 +1,231 @@
|
|||
/***************************************************************************
|
||||
* FileQueue.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Buffers;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public delegate void FileCommitCallback(FileQueue.Chunk chunk);
|
||||
|
||||
public sealed class FileQueue : IDisposable
|
||||
{
|
||||
private static int bufferSize;
|
||||
|
||||
private Chunk[] active;
|
||||
private int activeCount;
|
||||
private Page buffered;
|
||||
|
||||
private FileCommitCallback callback;
|
||||
|
||||
private ManualResetEvent idle;
|
||||
|
||||
private Queue<Page> pending;
|
||||
|
||||
private object syncRoot;
|
||||
|
||||
static FileQueue()
|
||||
{
|
||||
bufferSize = FileOperations.BufferSize;
|
||||
}
|
||||
|
||||
public FileQueue(int concurrentWrites, FileCommitCallback callback)
|
||||
{
|
||||
if (concurrentWrites < 1) throw new ArgumentOutOfRangeException("concurrentWrites");
|
||||
|
||||
if (bufferSize < 1)
|
||||
throw new ArgumentOutOfRangeException("bufferSize");
|
||||
|
||||
syncRoot = new object();
|
||||
|
||||
active = new Chunk[concurrentWrites];
|
||||
pending = new Queue<Page>();
|
||||
|
||||
this.callback = callback;
|
||||
|
||||
idle = new ManualResetEvent(true);
|
||||
}
|
||||
|
||||
public long Position{ get; private set; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (idle != null)
|
||||
{
|
||||
idle.Close();
|
||||
idle = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void Append(Page page)
|
||||
{
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (activeCount == 0) idle.Reset();
|
||||
|
||||
++activeCount;
|
||||
|
||||
for (int slot = 0; slot < active.Length; ++slot)
|
||||
if (active[slot] == null)
|
||||
{
|
||||
active[slot] = new Chunk(this, slot, page.buffer, 0, page.length);
|
||||
|
||||
callback(active[slot]);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
pending.Enqueue(page);
|
||||
}
|
||||
}
|
||||
|
||||
public void Flush()
|
||||
{
|
||||
if (buffered.buffer != null)
|
||||
{
|
||||
Append(buffered);
|
||||
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
|
||||
/*lock ( syncRoot ) {
|
||||
if ( pending.Count > 0 ) {
|
||||
idle.Reset();
|
||||
}
|
||||
|
||||
for ( int slot = 0; slot < active.Length && pending.Count > 0; ++slot ) {
|
||||
if ( active[slot] == null ) {
|
||||
Page page = pending.Dequeue();
|
||||
|
||||
active[slot] = new Chunk( this, slot, page.buffer, 0, page.length );
|
||||
|
||||
++activeCount;
|
||||
|
||||
callback( active[slot] );
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
idle.WaitOne();
|
||||
}
|
||||
|
||||
private void Commit(Chunk chunk, int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= active.Length) throw new ArgumentOutOfRangeException("slot");
|
||||
|
||||
lock (syncRoot)
|
||||
{
|
||||
if (active[slot] != chunk) throw new ArgumentException();
|
||||
|
||||
ArrayPool<byte>.Shared.Return(chunk.Buffer);
|
||||
|
||||
if (pending.Count > 0)
|
||||
{
|
||||
Page page = pending.Dequeue();
|
||||
|
||||
active[slot] = new Chunk(this, slot, page.buffer, 0, page.length);
|
||||
|
||||
callback(active[slot]);
|
||||
}
|
||||
else
|
||||
{
|
||||
active[slot] = null;
|
||||
}
|
||||
|
||||
--activeCount;
|
||||
|
||||
if (activeCount == 0) idle.Set();
|
||||
}
|
||||
}
|
||||
|
||||
public void Enqueue(byte[] buffer, int offset, int size)
|
||||
{
|
||||
if (buffer == null) throw new ArgumentNullException("buffer");
|
||||
|
||||
if (offset < 0) throw new ArgumentOutOfRangeException("offset");
|
||||
if (size < 0) throw new ArgumentOutOfRangeException("size");
|
||||
if (buffer.Length - offset < size) throw new ArgumentException();
|
||||
|
||||
Position += size;
|
||||
|
||||
while (size > 0)
|
||||
{
|
||||
if (buffered.buffer == null)
|
||||
buffered.buffer = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||
|
||||
byte[] page = buffered.buffer; // buffer page
|
||||
int pageSpace = page.Length - buffered.length; // available bytes in page
|
||||
int byteCount = size > pageSpace ? pageSpace : size; // how many bytes we can copy over
|
||||
|
||||
Buffer.BlockCopy(buffer, offset, page, buffered.length, byteCount);
|
||||
|
||||
buffered.length += byteCount;
|
||||
offset += byteCount;
|
||||
size -= byteCount;
|
||||
|
||||
if (buffered.length == page.Length)
|
||||
{
|
||||
// page full
|
||||
Append(buffered);
|
||||
|
||||
buffered.buffer = null;
|
||||
buffered.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Chunk
|
||||
{
|
||||
private int offset;
|
||||
private FileQueue owner;
|
||||
private int slot;
|
||||
|
||||
public Chunk(FileQueue owner, int slot, byte[] buffer, int offset, int size)
|
||||
{
|
||||
this.owner = owner;
|
||||
this.slot = slot;
|
||||
|
||||
Buffer = buffer;
|
||||
this.offset = offset;
|
||||
Size = size;
|
||||
}
|
||||
|
||||
public byte[] Buffer{ get; }
|
||||
|
||||
public int Offset => 0;
|
||||
|
||||
public int Size{ get; }
|
||||
|
||||
public void Commit()
|
||||
{
|
||||
owner.Commit(this, slot);
|
||||
}
|
||||
}
|
||||
|
||||
private struct Page
|
||||
{
|
||||
public byte[] buffer;
|
||||
public int length;
|
||||
}
|
||||
}
|
||||
}
|
||||
326
Projects/Server/Persistence/ParallelSaveStrategy.cs
Normal file
326
Projects/Server/Persistence/ParallelSaveStrategy.cs
Normal file
|
|
@ -0,0 +1,326 @@
|
|||
/***************************************************************************
|
||||
* ParallelSaveStrategy.cs
|
||||
* -------------------
|
||||
* begin : May 1, 2002
|
||||
* copyright : (C) The RunUO Software Team
|
||||
* email : info@runuo.com
|
||||
*
|
||||
* $Id$
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
/***************************************************************************
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading;
|
||||
using Server.Guilds;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class ParallelSaveStrategy : SaveStrategy
|
||||
{
|
||||
private Queue<Item> _decayQueue;
|
||||
|
||||
private Consumer[] consumers;
|
||||
private int cycle;
|
||||
|
||||
private bool finished;
|
||||
private SequentialFileWriter guildData, guildIndex;
|
||||
|
||||
private SequentialFileWriter itemData, itemIndex;
|
||||
|
||||
private SequentialFileWriter mobileData, mobileIndex;
|
||||
|
||||
private int processorCount;
|
||||
|
||||
public ParallelSaveStrategy(int processorCount)
|
||||
{
|
||||
this.processorCount = processorCount;
|
||||
|
||||
_decayQueue = new Queue<Item>();
|
||||
}
|
||||
|
||||
public override string Name => "Parallel";
|
||||
|
||||
private int GetThreadCount()
|
||||
{
|
||||
return processorCount - 1;
|
||||
}
|
||||
|
||||
public override void Save(bool permitBackgroundWrite)
|
||||
{
|
||||
OpenFiles();
|
||||
|
||||
consumers = new Consumer[GetThreadCount()];
|
||||
|
||||
for (int i = 0; i < consumers.Length; ++i) consumers[i] = new Consumer(this, 256);
|
||||
|
||||
IEnumerable<ISerializable> collection = new Producer();
|
||||
|
||||
foreach (ISerializable value in collection)
|
||||
while (!Enqueue(value))
|
||||
if (!Commit())
|
||||
Thread.Sleep(0);
|
||||
|
||||
finished = true;
|
||||
|
||||
SaveTypeDatabases();
|
||||
|
||||
WaitHandle.WaitAll(
|
||||
Array.ConvertAll<Consumer, WaitHandle>(
|
||||
consumers,
|
||||
input => input.completionEvent
|
||||
)
|
||||
);
|
||||
|
||||
Commit();
|
||||
|
||||
CloseFiles();
|
||||
}
|
||||
|
||||
public override void ProcessDecay()
|
||||
{
|
||||
while (_decayQueue.Count > 0)
|
||||
{
|
||||
Item item = _decayQueue.Dequeue();
|
||||
|
||||
if (item.OnDecay()) item.Delete();
|
||||
}
|
||||
}
|
||||
|
||||
private void SaveTypeDatabases()
|
||||
{
|
||||
SaveTypeDatabase(World.ItemTypesPath, World.m_ItemTypes);
|
||||
SaveTypeDatabase(World.MobileTypesPath, World.m_MobileTypes);
|
||||
}
|
||||
|
||||
private void SaveTypeDatabase(string path, List<Type> types)
|
||||
{
|
||||
BinaryFileWriter bfw = new BinaryFileWriter(path, false);
|
||||
|
||||
bfw.Write(types.Count);
|
||||
|
||||
foreach (Type type in types) bfw.Write(type.FullName);
|
||||
|
||||
bfw.Flush();
|
||||
|
||||
bfw.Close();
|
||||
}
|
||||
|
||||
private void OpenFiles()
|
||||
{
|
||||
itemData = new SequentialFileWriter(World.ItemDataPath);
|
||||
itemIndex = new SequentialFileWriter(World.ItemIndexPath);
|
||||
|
||||
mobileData = new SequentialFileWriter(World.MobileDataPath);
|
||||
mobileIndex = new SequentialFileWriter(World.MobileIndexPath);
|
||||
|
||||
guildData = new SequentialFileWriter(World.GuildDataPath);
|
||||
guildIndex = new SequentialFileWriter(World.GuildIndexPath);
|
||||
|
||||
WriteCount(itemIndex, World.Items.Count);
|
||||
WriteCount(mobileIndex, World.Mobiles.Count);
|
||||
WriteCount(guildIndex, BaseGuild.List.Count);
|
||||
}
|
||||
|
||||
private void WriteCount(SequentialFileWriter indexFile, int count)
|
||||
{
|
||||
byte[] buffer = new byte[4];
|
||||
|
||||
buffer[0] = (byte)count;
|
||||
buffer[1] = (byte)(count >> 8);
|
||||
buffer[2] = (byte)(count >> 16);
|
||||
buffer[3] = (byte)(count >> 24);
|
||||
|
||||
indexFile.Write(buffer, 0, buffer.Length);
|
||||
}
|
||||
|
||||
private void CloseFiles()
|
||||
{
|
||||
itemData.Close();
|
||||
itemIndex.Close();
|
||||
|
||||
mobileData.Close();
|
||||
mobileIndex.Close();
|
||||
|
||||
guildData.Close();
|
||||
guildIndex.Close();
|
||||
|
||||
World.NotifyDiskWriteComplete();
|
||||
}
|
||||
|
||||
private void OnSerialized(ConsumableEntry entry)
|
||||
{
|
||||
ISerializable value = entry.value;
|
||||
BinaryMemoryWriter writer = entry.writer;
|
||||
|
||||
if (value is Item item)
|
||||
Save(item, writer);
|
||||
else if (value is Mobile mob)
|
||||
Save(mob, writer);
|
||||
else if (value is BaseGuild guild)
|
||||
Save(guild, writer);
|
||||
}
|
||||
|
||||
private void Save(Item item, BinaryMemoryWriter writer)
|
||||
{
|
||||
writer.CommitTo(itemData, itemIndex, item.m_TypeRef, item.Serial);
|
||||
|
||||
if (item.Decays && item.Parent == null && item.Map != Map.Internal &&
|
||||
DateTime.UtcNow > item.LastMoved + item.DecayTime) _decayQueue.Enqueue(item);
|
||||
}
|
||||
|
||||
private void Save(Mobile mob, BinaryMemoryWriter writer)
|
||||
{
|
||||
writer.CommitTo(mobileData, mobileIndex, mob.m_TypeRef, mob.Serial);
|
||||
}
|
||||
|
||||
private void Save(BaseGuild guild, BinaryMemoryWriter writer)
|
||||
{
|
||||
writer.CommitTo(guildData, guildIndex, 0, guild.Id);
|
||||
}
|
||||
|
||||
private bool Enqueue(ISerializable value)
|
||||
{
|
||||
for (int i = 0; i < consumers.Length; ++i)
|
||||
{
|
||||
Consumer consumer = consumers[cycle++ % consumers.Length];
|
||||
|
||||
if (consumer.tail - consumer.head < consumer.buffer.Length)
|
||||
{
|
||||
consumer.buffer[consumer.tail % consumer.buffer.Length].value = value;
|
||||
consumer.tail++;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private bool Commit()
|
||||
{
|
||||
bool committed = false;
|
||||
|
||||
for (int i = 0; i < consumers.Length; ++i)
|
||||
{
|
||||
Consumer consumer = consumers[i];
|
||||
|
||||
while (consumer.head < consumer.done)
|
||||
{
|
||||
OnSerialized(consumer.buffer[consumer.head % consumer.buffer.Length]);
|
||||
consumer.head++;
|
||||
|
||||
committed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return committed;
|
||||
}
|
||||
|
||||
private sealed class Producer : IEnumerable<ISerializable>
|
||||
{
|
||||
private IEnumerable<BaseGuild> guilds;
|
||||
private IEnumerable<Item> items;
|
||||
private IEnumerable<Mobile> mobiles;
|
||||
|
||||
public Producer()
|
||||
{
|
||||
items = World.Items.Values;
|
||||
mobiles = World.Mobiles.Values;
|
||||
guilds = BaseGuild.List.Values;
|
||||
}
|
||||
|
||||
public IEnumerator<ISerializable> GetEnumerator()
|
||||
{
|
||||
foreach (Item item in items) yield return item;
|
||||
|
||||
foreach (Mobile mob in mobiles) yield return mob;
|
||||
|
||||
foreach (BaseGuild guild in guilds) yield return guild;
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
private struct ConsumableEntry
|
||||
{
|
||||
public ISerializable value;
|
||||
public BinaryMemoryWriter writer;
|
||||
}
|
||||
|
||||
private sealed class Consumer
|
||||
{
|
||||
public ConsumableEntry[] buffer;
|
||||
|
||||
public ManualResetEvent completionEvent;
|
||||
public int head, done, tail;
|
||||
private ParallelSaveStrategy owner;
|
||||
|
||||
private Thread thread;
|
||||
|
||||
public Consumer(ParallelSaveStrategy owner, int bufferSize)
|
||||
{
|
||||
this.owner = owner;
|
||||
|
||||
buffer = new ConsumableEntry[bufferSize];
|
||||
|
||||
for (int i = 0; i < buffer.Length; ++i) buffer[i].writer = new BinaryMemoryWriter();
|
||||
|
||||
completionEvent = new ManualResetEvent(false);
|
||||
|
||||
thread = new Thread(Processor);
|
||||
|
||||
thread.Name = "Parallel Serialization Thread";
|
||||
|
||||
thread.Start();
|
||||
}
|
||||
|
||||
private void Processor()
|
||||
{
|
||||
try
|
||||
{
|
||||
while (!owner.finished)
|
||||
{
|
||||
Process();
|
||||
Thread.Sleep(0);
|
||||
}
|
||||
|
||||
Process();
|
||||
|
||||
completionEvent.Set();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void Process()
|
||||
{
|
||||
ConsumableEntry entry;
|
||||
|
||||
while (done < tail)
|
||||
{
|
||||
entry = buffer[done % buffer.Length];
|
||||
|
||||
entry.value.Serialize(entry.writer);
|
||||
|
||||
++done;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
107
Projects/Server/Persistence/Persistence.cs
Normal file
107
Projects/Server/Persistence/Persistence.cs
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#region References
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
#endregion
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public static class Persistence
|
||||
{
|
||||
public static void Serialize(string path, Action<GenericWriter> serializer)
|
||||
{
|
||||
Serialize(new FileInfo(path), serializer);
|
||||
}
|
||||
|
||||
public static void Serialize(FileInfo file, Action<GenericWriter> serializer)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Directory?.Exists == false)
|
||||
file.Directory.Create();
|
||||
|
||||
if (!file.Exists) file.Create().Close();
|
||||
|
||||
file.Refresh();
|
||||
|
||||
using (FileStream fs = file.OpenWrite())
|
||||
{
|
||||
BinaryFileWriter writer = new BinaryFileWriter(fs, true);
|
||||
|
||||
try
|
||||
{
|
||||
serializer(writer);
|
||||
}
|
||||
finally
|
||||
{
|
||||
writer.Flush();
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(path, deserializer, true);
|
||||
}
|
||||
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer)
|
||||
{
|
||||
Deserialize(file, deserializer, true);
|
||||
}
|
||||
|
||||
public static void Deserialize(string path, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
Deserialize(new FileInfo(path), deserializer, ensure);
|
||||
}
|
||||
|
||||
public static void Deserialize(FileInfo file, Action<GenericReader> deserializer, bool ensure)
|
||||
{
|
||||
file.Refresh();
|
||||
|
||||
if (file.Directory?.Exists == false)
|
||||
{
|
||||
if (!ensure)
|
||||
throw new DirectoryNotFoundException();
|
||||
|
||||
file.Directory.Create();
|
||||
}
|
||||
|
||||
if (!file.Exists)
|
||||
{
|
||||
if (!ensure)
|
||||
throw new FileNotFoundException
|
||||
{
|
||||
Source = file.FullName
|
||||
};
|
||||
|
||||
file.Create().Close();
|
||||
}
|
||||
|
||||
file.Refresh();
|
||||
|
||||
using (FileStream fs = file.OpenRead())
|
||||
{
|
||||
BinaryFileReader reader = new BinaryFileReader(new BinaryReader(fs));
|
||||
|
||||
try
|
||||
{
|
||||
deserializer(reader);
|
||||
}
|
||||
catch (EndOfStreamException eos)
|
||||
{
|
||||
if (file.Length > 0) Console.WriteLine("[Persistence]: {0}", eos);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("[Persistence]: {0}", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
reader.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
116
Projects/Server/Persistence/QueuedMemoryWriter.cs
Normal file
116
Projects/Server/Persistence/QueuedMemoryWriter.cs
Normal file
|
|
@ -0,0 +1,116 @@
|
|||
/***************************************************************************
|
||||
* QueuedMemoryWriter.cs
|
||||
* -------------------
|
||||
* begin : December 16, 2010
|
||||
* 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.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public sealed class QueuedMemoryWriter : BinaryFileWriter
|
||||
{
|
||||
private MemoryStream _memStream;
|
||||
private List<IndexInfo> _orderedIndexInfo = new List<IndexInfo>();
|
||||
|
||||
public QueuedMemoryWriter()
|
||||
: base(new MemoryStream(1024 * 1024), true)
|
||||
{
|
||||
_memStream = UnderlyingStream as MemoryStream;
|
||||
}
|
||||
|
||||
protected override int BufferSize => 512;
|
||||
|
||||
public void QueueForIndex(ISerializable serializable, int size)
|
||||
{
|
||||
IndexInfo info;
|
||||
|
||||
info.size = size;
|
||||
|
||||
info.typeCode = serializable.TypeReference; //For guilds, this will automagically be zero.
|
||||
info.serial = serializable.SerialIdentity;
|
||||
|
||||
_orderedIndexInfo.Add(info);
|
||||
}
|
||||
|
||||
public void CommitTo(SequentialFileWriter dataFile, SequentialFileWriter indexFile)
|
||||
{
|
||||
Flush();
|
||||
|
||||
int memLength = (int)_memStream.Position;
|
||||
|
||||
if (memLength > 0)
|
||||
{
|
||||
byte[] memBuffer = _memStream.GetBuffer();
|
||||
|
||||
long actualPosition = dataFile.Position;
|
||||
|
||||
dataFile.Write(memBuffer, 0, memLength); //The buffer contains the data from many items.
|
||||
|
||||
//Console.WriteLine("Writing {0} bytes starting at {1}, with {2} things", memLength, actualPosition, _orderedIndexInfo.Count);
|
||||
|
||||
byte[] indexBuffer = new byte[20];
|
||||
|
||||
//int indexWritten = _orderedIndexInfo.Count * indexBuffer.Length;
|
||||
//int totalWritten = memLength + indexWritten
|
||||
|
||||
for (int i = 0; i < _orderedIndexInfo.Count; i++)
|
||||
{
|
||||
IndexInfo info = _orderedIndexInfo[i];
|
||||
|
||||
indexBuffer[0] = (byte)info.typeCode;
|
||||
indexBuffer[1] = (byte)(info.typeCode >> 8);
|
||||
indexBuffer[2] = (byte)(info.typeCode >> 16);
|
||||
indexBuffer[3] = (byte)(info.typeCode >> 24);
|
||||
|
||||
indexBuffer[4] = (byte)info.serial;
|
||||
indexBuffer[5] = (byte)(info.serial >> 8);
|
||||
indexBuffer[6] = (byte)(info.serial >> 16);
|
||||
indexBuffer[7] = (byte)(info.serial >> 24);
|
||||
|
||||
indexBuffer[8] = (byte)actualPosition;
|
||||
indexBuffer[9] = (byte)(actualPosition >> 8);
|
||||
indexBuffer[10] = (byte)(actualPosition >> 16);
|
||||
indexBuffer[11] = (byte)(actualPosition >> 24);
|
||||
indexBuffer[12] = (byte)(actualPosition >> 32);
|
||||
indexBuffer[13] = (byte)(actualPosition >> 40);
|
||||
indexBuffer[14] = (byte)(actualPosition >> 48);
|
||||
indexBuffer[15] = (byte)(actualPosition >> 56);
|
||||
|
||||
indexBuffer[16] = (byte)info.size;
|
||||
indexBuffer[17] = (byte)(info.size >> 8);
|
||||
indexBuffer[18] = (byte)(info.size >> 16);
|
||||
indexBuffer[19] = (byte)(info.size >> 24);
|
||||
|
||||
indexFile.Write(indexBuffer, 0, indexBuffer.Length);
|
||||
|
||||
actualPosition += info.size;
|
||||
}
|
||||
}
|
||||
|
||||
Close(); //We're done with this writer.
|
||||
}
|
||||
|
||||
private struct IndexInfo
|
||||
{
|
||||
public int size;
|
||||
public int typeCode;
|
||||
public uint serial;
|
||||
}
|
||||
}
|
||||
}
|
||||
47
Projects/Server/Persistence/SaveStrategy.cs
Normal file
47
Projects/Server/Persistence/SaveStrategy.cs
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
/***************************************************************************
|
||||
* SaveStrategy.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.
|
||||
*
|
||||
***************************************************************************/
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class SaveStrategy
|
||||
{
|
||||
public abstract string Name{ get; }
|
||||
|
||||
public static SaveStrategy Acquire()
|
||||
{
|
||||
if (Core.MultiProcessor)
|
||||
{
|
||||
int processorCount = Core.ProcessorCount;
|
||||
|
||||
if (processorCount > 2)
|
||||
return
|
||||
new DualSaveStrategy(); // return new DynamicSaveStrategy(); (4.0 or return new ParallelSaveStrategy(processorCount); (2.0)
|
||||
|
||||
return new DualSaveStrategy();
|
||||
}
|
||||
|
||||
return new StandardSaveStrategy();
|
||||
}
|
||||
|
||||
public abstract void Save(bool permitBackgroundWrite);
|
||||
|
||||
public abstract void ProcessDecay();
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue