765 lines
21 KiB
C#
765 lines
21 KiB
C#
using System;
|
|
using System.Reflection;
|
|
using System.Collections;
|
|
using Server;
|
|
using Server.Commands.Generic;
|
|
using Server.Gumps;
|
|
using Server.Network;
|
|
using Server.Menus;
|
|
using Server.Menus.Questions;
|
|
using Server.Targeting;
|
|
using CPA = Server.CommandPropertyAttribute;
|
|
|
|
namespace Server.EventSystem
|
|
{
|
|
public class EventPropertiesGump : Gump
|
|
{
|
|
private ArrayList m_List;
|
|
private int m_Page;
|
|
private Mobile m_Mobile;
|
|
private object m_Object;
|
|
private Stack m_Stack;
|
|
|
|
public static readonly bool OldStyle = PropsConfig.OldStyle;
|
|
|
|
public static readonly int GumpOffsetX = PropsConfig.GumpOffsetX;
|
|
public static readonly int GumpOffsetY = PropsConfig.GumpOffsetY;
|
|
|
|
public static readonly int TextHue = PropsConfig.TextHue;
|
|
public static readonly int TextOffsetX = PropsConfig.TextOffsetX;
|
|
|
|
public static readonly int OffsetGumpID = PropsConfig.OffsetGumpID;
|
|
public static readonly int HeaderGumpID = PropsConfig.HeaderGumpID;
|
|
public static readonly int EntryGumpID = PropsConfig.EntryGumpID;
|
|
public static readonly int BackGumpID = PropsConfig.BackGumpID;
|
|
public static readonly int SetGumpID = PropsConfig.SetGumpID;
|
|
|
|
public static readonly int SetWidth = PropsConfig.SetWidth;
|
|
public static readonly int SetOffsetX = PropsConfig.SetOffsetX, SetOffsetY = PropsConfig.SetOffsetY;
|
|
public static readonly int SetButtonID1 = PropsConfig.SetButtonID1;
|
|
public static readonly int SetButtonID2 = PropsConfig.SetButtonID2;
|
|
|
|
public static readonly int PrevWidth = PropsConfig.PrevWidth;
|
|
public static readonly int PrevOffsetX = PropsConfig.PrevOffsetX, PrevOffsetY = PropsConfig.PrevOffsetY;
|
|
public static readonly int PrevButtonID1 = PropsConfig.PrevButtonID1;
|
|
public static readonly int PrevButtonID2 = PropsConfig.PrevButtonID2;
|
|
|
|
public static readonly int NextWidth = PropsConfig.NextWidth;
|
|
public static readonly int NextOffsetX = PropsConfig.NextOffsetX, NextOffsetY = PropsConfig.NextOffsetY;
|
|
public static readonly int NextButtonID1 = PropsConfig.NextButtonID1;
|
|
public static readonly int NextButtonID2 = PropsConfig.NextButtonID2;
|
|
|
|
public static readonly int OffsetSize = PropsConfig.OffsetSize;
|
|
|
|
public static readonly int EntryHeight = PropsConfig.EntryHeight;
|
|
public static readonly int BorderSize = PropsConfig.BorderSize;
|
|
|
|
private static bool PrevLabel = OldStyle, NextLabel = OldStyle;
|
|
|
|
private static readonly int PrevLabelOffsetX = PrevWidth + 1;
|
|
private static readonly int PrevLabelOffsetY = 0;
|
|
|
|
private static readonly int NextLabelOffsetX = -29;
|
|
private static readonly int NextLabelOffsetY = 0;
|
|
|
|
private static readonly int NameWidth = 107;
|
|
private static readonly int ValueWidth = 128;
|
|
|
|
private static readonly int EntryCount = 15;
|
|
|
|
private static readonly int TypeWidth = NameWidth + OffsetSize + ValueWidth;
|
|
|
|
private static readonly int TotalWidth = OffsetSize + NameWidth + OffsetSize + ValueWidth + OffsetSize + SetWidth + OffsetSize;
|
|
private static readonly int TotalHeight = OffsetSize + ( ( EntryHeight + OffsetSize ) * ( EntryCount + 1 ) );
|
|
|
|
private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize;
|
|
private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize;
|
|
|
|
public EventPropertiesGump( Mobile mobile, object o )
|
|
: base( GumpOffsetX, GumpOffsetY )
|
|
{
|
|
m_Mobile = mobile;
|
|
m_Object = o;
|
|
m_List = BuildList();
|
|
|
|
Initialize( 0 );
|
|
}
|
|
|
|
public EventPropertiesGump( Mobile mobile, object o, Stack stack, StackEntry parent )
|
|
: base( GumpOffsetX, GumpOffsetY )
|
|
{
|
|
m_Mobile = mobile;
|
|
m_Object = o;
|
|
m_Stack = stack;
|
|
m_List = BuildList();
|
|
|
|
if ( parent != null )
|
|
{
|
|
if ( m_Stack == null )
|
|
m_Stack = new Stack();
|
|
|
|
m_Stack.Push( parent );
|
|
}
|
|
|
|
Initialize( 0 );
|
|
}
|
|
|
|
public EventPropertiesGump( Mobile mobile, object o, Stack stack, ArrayList list, int page )
|
|
: base( GumpOffsetX, GumpOffsetY )
|
|
{
|
|
m_Mobile = mobile;
|
|
m_Object = o;
|
|
m_List = list;
|
|
m_Stack = stack;
|
|
|
|
Initialize( page );
|
|
}
|
|
|
|
private void Initialize( int page )
|
|
{
|
|
m_Page = page;
|
|
|
|
int count = m_List.Count - ( page * EntryCount );
|
|
|
|
if ( count < 0 )
|
|
count = 0;
|
|
else if ( count > EntryCount )
|
|
count = EntryCount;
|
|
|
|
int lastIndex = ( page * EntryCount ) + count - 1;
|
|
|
|
if ( lastIndex >= 0 && lastIndex < m_List.Count && m_List[lastIndex] == null )
|
|
--count;
|
|
|
|
int totalHeight = OffsetSize + ( ( EntryHeight + OffsetSize ) * ( count + 1 ) );
|
|
|
|
AddPage( 0 );
|
|
|
|
AddBackground( 0, 0, BackWidth, BorderSize + totalHeight + BorderSize, BackGumpID );
|
|
AddImageTiled( BorderSize, BorderSize, TotalWidth - ( OldStyle ? SetWidth + OffsetSize : 0 ), totalHeight, OffsetGumpID );
|
|
|
|
int x = BorderSize + OffsetSize;
|
|
int y = BorderSize + OffsetSize;
|
|
|
|
int emptyWidth = TotalWidth - PrevWidth - NextWidth - ( OffsetSize * 4 ) - ( OldStyle ? SetWidth + OffsetSize : 0 );
|
|
|
|
if ( OldStyle )
|
|
AddImageTiled( x, y, TotalWidth - ( OffsetSize * 3 ) - SetWidth, EntryHeight, HeaderGumpID );
|
|
else
|
|
AddImageTiled( x, y, PrevWidth, EntryHeight, HeaderGumpID );
|
|
|
|
if ( page > 0 )
|
|
{
|
|
AddButton( x + PrevOffsetX, y + PrevOffsetY, PrevButtonID1, PrevButtonID2, 1, GumpButtonType.Reply, 0 );
|
|
|
|
if ( PrevLabel )
|
|
AddLabel( x + PrevLabelOffsetX, y + PrevLabelOffsetY, TextHue, "Previous" );
|
|
}
|
|
|
|
x += PrevWidth + OffsetSize;
|
|
|
|
if ( !OldStyle )
|
|
AddImageTiled( x - ( OldStyle ? OffsetSize : 0 ), y, emptyWidth + ( OldStyle ? OffsetSize * 2 : 0 ), EntryHeight, HeaderGumpID );
|
|
|
|
x += emptyWidth + OffsetSize;
|
|
|
|
if ( !OldStyle )
|
|
AddImageTiled( x, y, NextWidth, EntryHeight, HeaderGumpID );
|
|
|
|
if ( ( page + 1 ) * EntryCount < m_List.Count )
|
|
{
|
|
AddButton( x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 2, GumpButtonType.Reply, 1 );
|
|
|
|
if ( NextLabel )
|
|
AddLabel( x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next" );
|
|
}
|
|
|
|
for ( int i = 0, index = page * EntryCount; i < count && index < m_List.Count; ++i, ++index )
|
|
{
|
|
x = BorderSize + OffsetSize;
|
|
y += EntryHeight + OffsetSize;
|
|
|
|
object o = m_List[index];
|
|
|
|
if ( o == null )
|
|
{
|
|
AddImageTiled( x - OffsetSize, y, TotalWidth, EntryHeight, BackGumpID + 4 );
|
|
}
|
|
else if ( o is Type )
|
|
{
|
|
Type type = (Type)o;
|
|
|
|
AddImageTiled( x, y, TypeWidth, EntryHeight, EntryGumpID );
|
|
AddLabelCropped( x + TextOffsetX, y, TypeWidth - TextOffsetX, EntryHeight, TextHue, type.Name );
|
|
x += TypeWidth + OffsetSize;
|
|
|
|
if ( SetGumpID != 0 )
|
|
AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID );
|
|
}
|
|
else if ( o is PropertyInfo )
|
|
{
|
|
PropertyInfo prop = (PropertyInfo)o;
|
|
|
|
AddImageTiled( x, y, NameWidth, EntryHeight, EntryGumpID );
|
|
AddLabelCropped( x + TextOffsetX, y, NameWidth - TextOffsetX, EntryHeight, TextHue, prop.Name );
|
|
x += NameWidth + OffsetSize;
|
|
AddImageTiled( x, y, ValueWidth, EntryHeight, EntryGumpID );
|
|
AddLabelCropped( x + TextOffsetX, y, ValueWidth - TextOffsetX, EntryHeight, TextHue, ValueToString( prop ) );
|
|
x += ValueWidth + OffsetSize;
|
|
|
|
if ( SetGumpID != 0 )
|
|
AddImageTiled( x, y, SetWidth, EntryHeight, SetGumpID );
|
|
|
|
CPA cpa = GetCPA( prop );
|
|
|
|
if ( prop.CanWrite && cpa != null && m_Mobile.AccessLevel >= cpa.WriteLevel && !cpa.ReadOnly )
|
|
AddButton( x + SetOffsetX, y + SetOffsetY, SetButtonID1, SetButtonID2, i + 3, GumpButtonType.Reply, 0 );
|
|
}
|
|
}
|
|
}
|
|
|
|
public static string[] m_BoolNames = new string[] { "True", "False" };
|
|
public static object[] m_BoolValues = new object[] { true, false };
|
|
|
|
public static string[] m_PoisonNames = new string[] { "None", "Lesser", "Regular", "Greater", "Deadly", "Lethal" };
|
|
public static object[] m_PoisonValues = new object[] { null, Poison.Lesser, Poison.Regular, Poison.Greater, Poison.Deadly, Poison.Lethal };
|
|
|
|
public class StackEntry
|
|
{
|
|
public object m_Object;
|
|
public PropertyInfo m_Property;
|
|
|
|
public StackEntry( object obj, PropertyInfo prop )
|
|
{
|
|
m_Object = obj;
|
|
m_Property = prop;
|
|
}
|
|
}
|
|
|
|
public override void OnResponse( NetState state, RelayInfo info )
|
|
{
|
|
Mobile from = state.Mobile;
|
|
|
|
if ( !BaseCommand.IsAccessible( from, m_Object ) )
|
|
{
|
|
from.SendMessage( "You may no longer access their properties." );
|
|
return;
|
|
}
|
|
|
|
switch ( info.ButtonID )
|
|
{
|
|
case 0: // Closed
|
|
{
|
|
if ( m_Stack != null && m_Stack.Count > 0 )
|
|
{
|
|
StackEntry entry = (StackEntry)m_Stack.Pop();
|
|
|
|
from.SendGump( new EventPropertiesGump( from, entry.m_Object, m_Stack, null ) );
|
|
}
|
|
|
|
break;
|
|
}
|
|
case 1: // Previous
|
|
{
|
|
if ( m_Page > 0 )
|
|
from.SendGump( new EventPropertiesGump( from, m_Object, m_Stack, m_List, m_Page - 1 ) );
|
|
|
|
break;
|
|
}
|
|
case 2: // Next
|
|
{
|
|
if ( ( m_Page + 1 ) * EntryCount < m_List.Count )
|
|
from.SendGump( new EventPropertiesGump( from, m_Object, m_Stack, m_List, m_Page + 1 ) );
|
|
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
int index = ( m_Page * EntryCount ) + ( info.ButtonID - 3 );
|
|
|
|
if ( index >= 0 && index < m_List.Count )
|
|
{
|
|
PropertyInfo prop = m_List[index] as PropertyInfo;
|
|
|
|
if ( prop == null )
|
|
return;
|
|
|
|
CPA attr = GetCPA( prop );
|
|
|
|
if ( !prop.CanWrite || attr == null || from.AccessLevel < attr.WriteLevel || attr.ReadOnly )
|
|
return;
|
|
|
|
Type type = prop.PropertyType;
|
|
|
|
if ( IsType( type, typeofMobile ) || IsType( type, typeofItem ) )
|
|
from.SendGump( new EventSetObjectGump( prop, from, m_Object, m_Stack, type, m_Page, m_List ) );
|
|
else if ( IsType( type, typeofType ) )
|
|
from.Target = new EventSetObjectTarget( prop, from, m_Object, m_Stack, type, m_Page, m_List );
|
|
else if ( IsType( type, typeofPoint3D ) )
|
|
from.SendGump( new EventSetPoint3DGump( prop, from, m_Object, m_Stack, m_Page, m_List ) );
|
|
else if ( IsType( type, typeofPoint2D ) )
|
|
from.SendGump( new EventSetPoint2DGump( prop, from, m_Object, m_Stack, m_Page, m_List ) );
|
|
else if ( IsType( type, typeofTimeSpan ) )
|
|
from.SendGump( new EventSetTimeSpanGump( prop, from, m_Object, m_Stack, m_Page, m_List ) );
|
|
else if ( IsCustomEnum( type ) )
|
|
from.SendGump( new EventSetCustomEnumGump( prop, from, m_Object, m_Stack, m_Page, m_List, GetCustomEnumNames( type ) ) );
|
|
else if ( IsType( type, typeofEnum ) )
|
|
from.SendGump( new EventSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, Enum.GetNames( type ), GetObjects( Enum.GetValues( type ) ) ) );
|
|
else if ( IsType( type, typeofBool ) )
|
|
from.SendGump( new EventSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_BoolNames, m_BoolValues ) );
|
|
else if ( IsType( type, typeofString ) || IsType( type, typeofReal ) || IsType( type, typeofNumeric ) )
|
|
from.SendGump( new EventSetGump( prop, from, m_Object, m_Stack, m_Page, m_List ) );
|
|
else if ( IsType( type, typeofPoison ) )
|
|
from.SendGump( new EventSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, m_PoisonNames, m_PoisonValues ) );
|
|
else if ( IsType( type, typeofMap ) )
|
|
from.SendGump( new EventSetListOptionGump( prop, from, m_Object, m_Stack, m_Page, m_List, Map.GetMapNames(), Map.GetMapValues() ) );
|
|
else if ( IsType( type, typeofSkills ) && m_Object is Mobile )
|
|
{
|
|
from.SendGump( new EventPropertiesGump( from, m_Object, m_Stack, m_List, m_Page ) );
|
|
from.SendGump( new SkillsGump( from, (Mobile)m_Object ) );
|
|
}
|
|
else if ( HasAttribute( type, typeofPropertyObject, true ) )
|
|
{
|
|
object obj = prop.GetValue( m_Object, null );
|
|
|
|
if ( obj != null )
|
|
from.SendGump( new EventPropertiesGump( from, obj, m_Stack, new StackEntry( m_Object, prop ) ) );
|
|
else
|
|
from.SendGump( new EventPropertiesGump( from, m_Object, m_Stack, m_List, m_Page ) );
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
private static object[] GetObjects( Array a )
|
|
{
|
|
object[] list = new object[a.Length];
|
|
|
|
for ( int i = 0; i < list.Length; ++i )
|
|
list[i] = a.GetValue( i );
|
|
|
|
return list;
|
|
}
|
|
|
|
private static bool IsCustomEnum( Type type )
|
|
{
|
|
return type.IsDefined( typeofCustomEnum, false );
|
|
}
|
|
|
|
public static void OnValueChanged( object obj, PropertyInfo prop, Stack stack )
|
|
{
|
|
if ( stack == null || stack.Count == 0 )
|
|
return;
|
|
|
|
if ( !prop.PropertyType.IsValueType )
|
|
return;
|
|
|
|
StackEntry peek = (StackEntry)stack.Peek();
|
|
|
|
if ( peek.m_Property.CanWrite )
|
|
peek.m_Property.SetValue( peek.m_Object, obj, null );
|
|
}
|
|
|
|
private static string[] GetCustomEnumNames( Type type )
|
|
{
|
|
object[] attrs = type.GetCustomAttributes( typeofCustomEnum, false );
|
|
|
|
if ( attrs.Length == 0 )
|
|
return new string[0];
|
|
|
|
CustomEnumAttribute ce = attrs[0] as CustomEnumAttribute;
|
|
|
|
if ( ce == null )
|
|
return new string[0];
|
|
|
|
return ce.Names;
|
|
}
|
|
|
|
private static bool HasAttribute( Type type, Type check, bool inherit )
|
|
{
|
|
object[] objs = type.GetCustomAttributes( check, inherit );
|
|
|
|
return ( objs != null && objs.Length > 0 );
|
|
}
|
|
|
|
private static bool IsType( Type type, Type check )
|
|
{
|
|
return type == check || type.IsSubclassOf( check );
|
|
}
|
|
|
|
private static bool IsType( Type type, Type[] check )
|
|
{
|
|
for ( int i = 0; i < check.Length; ++i )
|
|
if ( IsType( type, check[i] ) )
|
|
return true;
|
|
|
|
return false;
|
|
}
|
|
|
|
private static Type typeofMobile = typeof( Mobile );
|
|
private static Type typeofItem = typeof( Item );
|
|
private static Type typeofType = typeof( Type );
|
|
private static Type typeofPoint3D = typeof( Point3D );
|
|
private static Type typeofPoint2D = typeof( Point2D );
|
|
private static Type typeofTimeSpan = typeof( TimeSpan );
|
|
private static Type typeofCustomEnum = typeof( CustomEnumAttribute );
|
|
private static Type typeofEnum = typeof( Enum );
|
|
private static Type typeofBool = typeof( Boolean );
|
|
private static Type typeofString = typeof( String );
|
|
private static Type typeofPoison = typeof( Poison );
|
|
private static Type typeofMap = typeof( Map );
|
|
private static Type typeofSkills = typeof( Skills );
|
|
private static Type typeofPropertyObject = typeof( PropertyObjectAttribute );
|
|
private static Type typeofNoSort = typeof( NoSortAttribute );
|
|
|
|
private static Type[] typeofReal = new Type[]
|
|
{
|
|
typeof( Single ),
|
|
typeof( Double )
|
|
};
|
|
|
|
private static Type[] typeofNumeric = new Type[]
|
|
{
|
|
typeof( Byte ),
|
|
typeof( Int16 ),
|
|
typeof( Int32 ),
|
|
typeof( Int64 ),
|
|
typeof( SByte ),
|
|
typeof( UInt16 ),
|
|
typeof( UInt32 ),
|
|
typeof( UInt64 )
|
|
};
|
|
|
|
private string ValueToString( PropertyInfo prop )
|
|
{
|
|
return ValueToString( m_Object, prop );
|
|
}
|
|
|
|
public static string ValueToString( object obj, PropertyInfo prop )
|
|
{
|
|
try
|
|
{
|
|
return ValueToString( prop.GetValue( obj, null ) );
|
|
}
|
|
catch ( Exception e )
|
|
{
|
|
return String.Format( "!{0}!", e.GetType() );
|
|
}
|
|
}
|
|
|
|
public static string ValueToString( object o )
|
|
{
|
|
if ( o == null )
|
|
{
|
|
return "-null-";
|
|
}
|
|
else if ( o is string )
|
|
{
|
|
return String.Format( "\"{0}\"", (string)o );
|
|
}
|
|
else if ( o is bool )
|
|
{
|
|
return o.ToString();
|
|
}
|
|
else if ( o is char )
|
|
{
|
|
return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o );
|
|
}
|
|
else if ( o is Serial )
|
|
{
|
|
Serial s = (Serial)o;
|
|
|
|
if ( s.IsValid )
|
|
{
|
|
if ( s.IsItem )
|
|
{
|
|
return String.Format( "(I) 0x{0:X}", s.Value );
|
|
}
|
|
else if ( s.IsMobile )
|
|
{
|
|
return String.Format( "(M) 0x{0:X}", s.Value );
|
|
}
|
|
}
|
|
|
|
return String.Format( "(?) 0x{0:X}", s.Value );
|
|
}
|
|
else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong )
|
|
{
|
|
return String.Format( "{0} (0x{0:X})", o );
|
|
}
|
|
else if ( o is Mobile )
|
|
{
|
|
return String.Format( "(M) 0x{0:X} \"{1}\"", ( (Mobile)o ).Serial.Value, ( (Mobile)o ).Name );
|
|
}
|
|
else if ( o is Item )
|
|
{
|
|
return String.Format( "(I) 0x{0:X}", ( (Item)o ).Serial );
|
|
}
|
|
else if ( o is Type )
|
|
{
|
|
return ( (Type)o ).Name;
|
|
}
|
|
else
|
|
{
|
|
return o.ToString();
|
|
}
|
|
}
|
|
|
|
private ArrayList BuildList()
|
|
{
|
|
Type type = m_Object.GetType();
|
|
|
|
PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public );
|
|
|
|
ArrayList groups = GetGroups( type, props );
|
|
ArrayList list = new ArrayList();
|
|
|
|
for ( int i = 0; i < groups.Count; ++i )
|
|
{
|
|
DictionaryEntry de = (DictionaryEntry)groups[i];
|
|
ArrayList groupList = (ArrayList)de.Value;
|
|
|
|
if ( !HasAttribute( (Type)de.Key, typeofNoSort, false ) )
|
|
groupList.Sort( PropertySorter.Instance );
|
|
|
|
if ( i != 0 )
|
|
list.Add( null );
|
|
|
|
list.Add( de.Key );
|
|
list.AddRange( groupList );
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private static Type typeofCPA = typeof( CPA );
|
|
private static Type typeofObject = typeof( object );
|
|
|
|
private static CPA GetCPA( PropertyInfo prop )
|
|
{
|
|
object[] attrs = prop.GetCustomAttributes( typeofCPA, false );
|
|
|
|
if ( attrs.Length > 0 )
|
|
return attrs[0] as CPA;
|
|
else
|
|
return null;
|
|
}
|
|
|
|
private ArrayList GetGroups( Type objectType, PropertyInfo[] props )
|
|
{
|
|
Hashtable groups = new Hashtable();
|
|
|
|
for ( int i = 0; i < props.Length; ++i )
|
|
{
|
|
PropertyInfo prop = props[i];
|
|
|
|
if ( prop.CanRead )
|
|
{
|
|
CPA attr = GetCPA( prop );
|
|
|
|
if ( attr != null && m_Mobile.AccessLevel >= attr.ReadLevel )
|
|
{
|
|
Type type = prop.DeclaringType;
|
|
|
|
while ( true )
|
|
{
|
|
Type baseType = type.BaseType;
|
|
|
|
if ( baseType == null || baseType == typeofObject )
|
|
break;
|
|
|
|
if ( baseType.GetProperty( prop.Name, prop.PropertyType ) != null )
|
|
type = baseType;
|
|
else
|
|
break;
|
|
}
|
|
|
|
ArrayList list = (ArrayList)groups[type];
|
|
|
|
if ( list == null )
|
|
groups[type] = list = new ArrayList();
|
|
|
|
list.Add( prop );
|
|
}
|
|
}
|
|
}
|
|
|
|
ArrayList sorted = new ArrayList( groups );
|
|
|
|
sorted.Sort( new GroupComparer( objectType ) );
|
|
|
|
return sorted;
|
|
}
|
|
|
|
public static object GetObjectFromString( Type t, string s )
|
|
{
|
|
if ( t == typeof( string ) )
|
|
{
|
|
return s;
|
|
}
|
|
else if ( t == typeof( byte ) || t == typeof( sbyte ) || t == typeof( short ) || t == typeof( ushort ) || t == typeof( int ) || t == typeof( uint ) || t == typeof( long ) || t == typeof( ulong ) )
|
|
{
|
|
if ( s.StartsWith( "0x" ) )
|
|
{
|
|
if ( t == typeof( ulong ) || t == typeof( uint ) || t == typeof( ushort ) || t == typeof( byte ) )
|
|
{
|
|
return Convert.ChangeType( Convert.ToUInt64( s.Substring( 2 ), 16 ), t );
|
|
}
|
|
else
|
|
{
|
|
return Convert.ChangeType( Convert.ToInt64( s.Substring( 2 ), 16 ), t );
|
|
}
|
|
}
|
|
else
|
|
{
|
|
return Convert.ChangeType( s, t );
|
|
}
|
|
}
|
|
else if ( t == typeof( double ) || t == typeof( float ) )
|
|
{
|
|
return Convert.ChangeType( s, t );
|
|
}
|
|
else if ( t.IsDefined( typeof( ParsableAttribute ), false ) )
|
|
{
|
|
MethodInfo parseMethod = t.GetMethod( "Parse", new Type[] { typeof( string ) } );
|
|
|
|
return parseMethod.Invoke( null, new object[] { s } );
|
|
}
|
|
|
|
throw new Exception( "bad" );
|
|
}
|
|
|
|
private static string GetStringFromObject( object o )
|
|
{
|
|
if ( o == null )
|
|
{
|
|
return "-null-";
|
|
}
|
|
else if ( o is string )
|
|
{
|
|
return String.Format( "\"{0}\"", (string)o );
|
|
}
|
|
else if ( o is bool )
|
|
{
|
|
return o.ToString();
|
|
}
|
|
else if ( o is char )
|
|
{
|
|
return String.Format( "0x{0:X} '{1}'", (int)(char)o, (char)o );
|
|
}
|
|
else if ( o is Serial )
|
|
{
|
|
Serial s = (Serial)o;
|
|
|
|
if ( s.IsValid )
|
|
{
|
|
if ( s.IsItem )
|
|
{
|
|
return String.Format( "(I) 0x{0:X}", s.Value );
|
|
}
|
|
else if ( s.IsMobile )
|
|
{
|
|
return String.Format( "(M) 0x{0:X}", s.Value );
|
|
}
|
|
}
|
|
|
|
return String.Format( "(?) 0x{0:X}", s.Value );
|
|
}
|
|
else if ( o is byte || o is sbyte || o is short || o is ushort || o is int || o is uint || o is long || o is ulong )
|
|
{
|
|
return String.Format( "{0} (0x{0:X})", o );
|
|
}
|
|
else if ( o is Mobile )
|
|
{
|
|
return String.Format( "(M) 0x{0:X} \"{1}\"", ( (Mobile)o ).Serial.Value, ( (Mobile)o ).Name );
|
|
}
|
|
else if ( o is Item )
|
|
{
|
|
return String.Format( "(I) 0x{0:X}", ( (Item)o ).Serial );
|
|
}
|
|
else if ( o is Type )
|
|
{
|
|
return ( (Type)o ).Name;
|
|
}
|
|
else
|
|
{
|
|
return o.ToString();
|
|
}
|
|
}
|
|
|
|
private class PropertySorter : IComparer
|
|
{
|
|
public static readonly PropertySorter Instance = new PropertySorter();
|
|
|
|
private PropertySorter()
|
|
{
|
|
}
|
|
|
|
public int Compare( object x, object y )
|
|
{
|
|
if ( x == null && y == null )
|
|
return 0;
|
|
else if ( x == null )
|
|
return -1;
|
|
else if ( y == null )
|
|
return 1;
|
|
|
|
PropertyInfo a = x as PropertyInfo;
|
|
PropertyInfo b = y as PropertyInfo;
|
|
|
|
if ( a == null || b == null )
|
|
throw new ArgumentException();
|
|
|
|
return a.Name.CompareTo( b.Name );
|
|
}
|
|
}
|
|
|
|
private class GroupComparer : IComparer
|
|
{
|
|
private Type m_Start;
|
|
|
|
public GroupComparer( Type start )
|
|
{
|
|
m_Start = start;
|
|
}
|
|
|
|
private static Type typeofObject = typeof( Object );
|
|
|
|
private int GetDistance( Type type )
|
|
{
|
|
Type current = m_Start;
|
|
|
|
int dist;
|
|
|
|
for ( dist = 0; current != null && current != typeofObject && current != type; ++dist )
|
|
current = current.BaseType;
|
|
|
|
return dist;
|
|
}
|
|
|
|
public int Compare( object x, object y )
|
|
{
|
|
if ( x == null && y == null )
|
|
return 0;
|
|
else if ( x == null )
|
|
return -1;
|
|
else if ( y == null )
|
|
return 1;
|
|
|
|
if ( !( x is DictionaryEntry ) || !( y is DictionaryEntry ) )
|
|
throw new ArgumentException();
|
|
|
|
DictionaryEntry de1 = (DictionaryEntry)x;
|
|
DictionaryEntry de2 = (DictionaryEntry)y;
|
|
|
|
Type a = (Type)de1.Key;
|
|
Type b = (Type)de2.Key;
|
|
|
|
return GetDistance( a ).CompareTo( GetDistance( b ) );
|
|
}
|
|
}
|
|
}
|
|
} |