#W# Initial Commit: Avatars Conquest
This commit is contained in:
commit
5df497787a
7510 changed files with 416048 additions and 0 deletions
837
Scripts/Commands/Properties.cs
Normal file
837
Scripts/Commands/Properties.cs
Normal file
|
|
@ -0,0 +1,837 @@
|
|||
using System;
|
||||
using System.Reflection;
|
||||
using System.Collections;
|
||||
using Server;
|
||||
using Server.Targeting;
|
||||
using Server.Items;
|
||||
using Server.Gumps;
|
||||
using CPA = Server.CommandPropertyAttribute;
|
||||
using Server.Commands;
|
||||
using Server.Commands.Generic;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public enum PropertyAccess
|
||||
{
|
||||
Read = 0x01,
|
||||
Write = 0x02,
|
||||
ReadWrite = Read | Write
|
||||
}
|
||||
|
||||
public class Properties
|
||||
{
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register( "Props", AccessLevel.Counselor, new CommandEventHandler( Props_OnCommand ) );
|
||||
}
|
||||
|
||||
private class PropsTarget : Target
|
||||
{
|
||||
public PropsTarget() : base( -1, true, TargetFlags.None )
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnTarget( Mobile from, object o )
|
||||
{
|
||||
if ( !BaseCommand.IsAccessible( from, o ) )
|
||||
from.SendMessage( "That is not accessible." );
|
||||
else
|
||||
from.SendGump( new PropertiesGump( from, o ) );
|
||||
}
|
||||
}
|
||||
|
||||
[Usage( "Props [serial]" )]
|
||||
[Description( "Opens a menu where you can view and edit all properties of a targeted (or specified) object." )]
|
||||
private static void Props_OnCommand( CommandEventArgs e )
|
||||
{
|
||||
if ( e.Length == 1 )
|
||||
{
|
||||
IEntity ent = World.FindEntity( e.GetInt32( 0 ) );
|
||||
|
||||
if ( ent == null )
|
||||
e.Mobile.SendMessage( "No object with that serial was found." );
|
||||
else if ( !BaseCommand.IsAccessible( e.Mobile, ent ) )
|
||||
e.Mobile.SendMessage( "That is not accessible." );
|
||||
else
|
||||
e.Mobile.SendGump( new PropertiesGump( e.Mobile, ent ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
e.Mobile.Target = new PropsTarget();
|
||||
}
|
||||
}
|
||||
|
||||
private static bool CIEqual( string l, string r )
|
||||
{
|
||||
return Insensitive.Equals( l, r );
|
||||
}
|
||||
|
||||
private static Type typeofCPA = typeof( CPA );
|
||||
|
||||
public static CPA GetCPA( PropertyInfo p )
|
||||
{
|
||||
object[] attrs = p.GetCustomAttributes( typeofCPA, false );
|
||||
|
||||
if ( attrs.Length == 0 )
|
||||
return null;
|
||||
|
||||
return attrs[0] as CPA;
|
||||
}
|
||||
|
||||
public static PropertyInfo[] GetPropertyInfoChain( Mobile from, Type type, string propertyString, PropertyAccess endAccess, ref string failReason )
|
||||
{
|
||||
string[] split = propertyString.Split( '.' );
|
||||
|
||||
if ( split.Length == 0 )
|
||||
return null;
|
||||
|
||||
PropertyInfo[] info = new PropertyInfo[split.Length];
|
||||
|
||||
for ( int i = 0; i < info.Length; ++i )
|
||||
{
|
||||
string propertyName = split[i];
|
||||
|
||||
if ( CIEqual( propertyName, "current" ) )
|
||||
continue;
|
||||
|
||||
PropertyInfo[] props = type.GetProperties( BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public );
|
||||
|
||||
bool isFinal = ( i == (info.Length - 1) );
|
||||
|
||||
PropertyAccess access = endAccess;
|
||||
|
||||
if ( !isFinal )
|
||||
access |= PropertyAccess.Read;
|
||||
|
||||
for ( int j = 0; j < props.Length; ++j )
|
||||
{
|
||||
PropertyInfo p = props[j];
|
||||
|
||||
if ( CIEqual( p.Name, propertyName ) )
|
||||
{
|
||||
CPA attr = GetCPA( p );
|
||||
|
||||
if ( attr == null )
|
||||
{
|
||||
failReason = String.Format( "Property '{0}' not found.", propertyName );
|
||||
return null;
|
||||
}
|
||||
else if ( (access & PropertyAccess.Read) != 0 && from.AccessLevel < attr.ReadLevel )
|
||||
{
|
||||
failReason = String.Format( "You must be at least {0} to get the property '{1}'.",
|
||||
Mobile.GetAccessLevelName( attr.ReadLevel ), propertyName );
|
||||
|
||||
return null;
|
||||
}
|
||||
else if ( (access & PropertyAccess.Write) != 0 && from.AccessLevel < attr.WriteLevel )
|
||||
{
|
||||
failReason = String.Format( "You must be at least {0} to set the property '{1}'.",
|
||||
Mobile.GetAccessLevelName( attr.WriteLevel ), propertyName );
|
||||
|
||||
return null;
|
||||
}
|
||||
else if ( (access & PropertyAccess.Read) != 0 && !p.CanRead )
|
||||
{
|
||||
failReason = String.Format( "Property '{0}' is write only.", propertyName );
|
||||
return null;
|
||||
}
|
||||
else if ( (access & PropertyAccess.Write) != 0 && (!p.CanWrite || attr.ReadOnly) && isFinal )
|
||||
{
|
||||
failReason = String.Format( "Property '{0}' is read only.", propertyName );
|
||||
return null;
|
||||
}
|
||||
|
||||
info[i] = p;
|
||||
type = p.PropertyType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( info[i] == null )
|
||||
{
|
||||
failReason = String.Format( "Property '{0}' not found.", propertyName );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public static PropertyInfo GetPropertyInfo( Mobile from, ref object obj, string propertyName, PropertyAccess access, ref string failReason )
|
||||
{
|
||||
PropertyInfo[] chain = GetPropertyInfoChain( from, obj.GetType(), propertyName, access, ref failReason );
|
||||
|
||||
if ( chain == null )
|
||||
return null;
|
||||
|
||||
return GetPropertyInfo( ref obj, chain, ref failReason );
|
||||
}
|
||||
|
||||
public static PropertyInfo GetPropertyInfo( ref object obj, PropertyInfo[] chain, ref string failReason )
|
||||
{
|
||||
if ( chain == null || chain.Length == 0 )
|
||||
{
|
||||
failReason = "Property chain is empty.";
|
||||
return null;
|
||||
}
|
||||
|
||||
for ( int i = 0; i < chain.Length - 1; ++i )
|
||||
{
|
||||
if ( chain[i] == null )
|
||||
continue;
|
||||
|
||||
obj = chain[i].GetValue( obj, null );
|
||||
|
||||
if ( obj == null )
|
||||
{
|
||||
failReason = String.Format( "Property '{0}' is null.", chain[i] );
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
return chain[chain.Length-1];
|
||||
}
|
||||
|
||||
public static string GetValue( Mobile from, object o, string name )
|
||||
{
|
||||
string failReason = "";
|
||||
|
||||
PropertyInfo[] chain = GetPropertyInfoChain( from, o.GetType(), name, PropertyAccess.Read, ref failReason );
|
||||
|
||||
if ( chain == null || chain.Length == 0 )
|
||||
return failReason;
|
||||
|
||||
PropertyInfo p = GetPropertyInfo( ref o, chain, ref failReason );
|
||||
|
||||
if ( p == null )
|
||||
return failReason;
|
||||
|
||||
return InternalGetValue( o, p, chain );
|
||||
}
|
||||
|
||||
public static string IncreaseValue( Mobile from, object o, string[] args )
|
||||
{
|
||||
Type type = o.GetType();
|
||||
|
||||
object[] realObjs = new object[args.Length/2];
|
||||
PropertyInfo[] realProps = new PropertyInfo[args.Length/2];
|
||||
int[] realValues = new int[args.Length/2];
|
||||
|
||||
bool positive = false, negative = false;
|
||||
|
||||
for ( int i = 0; i < realProps.Length; ++i )
|
||||
{
|
||||
string name = args[i*2];
|
||||
|
||||
try
|
||||
{
|
||||
string valueString = args[1 + (i*2)];
|
||||
|
||||
if ( valueString.StartsWith( "0x" ) )
|
||||
{
|
||||
realValues[i] = Convert.ToInt32( valueString.Substring( 2 ), 16 );
|
||||
}
|
||||
else
|
||||
{
|
||||
realValues[i] = Convert.ToInt32( valueString );
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Offset value could not be parsed.";
|
||||
}
|
||||
|
||||
if ( realValues[i] > 0 )
|
||||
positive = true;
|
||||
else if ( realValues[i] < 0 )
|
||||
negative = true;
|
||||
else
|
||||
return "Zero is not a valid value to offset.";
|
||||
|
||||
string failReason = null;
|
||||
realObjs[i] = o;
|
||||
realProps[i] = GetPropertyInfo( from, ref realObjs[i], name, PropertyAccess.ReadWrite, ref failReason );
|
||||
|
||||
if ( failReason != null )
|
||||
return failReason;
|
||||
|
||||
if ( realProps[i] == null )
|
||||
return "Property not found.";
|
||||
}
|
||||
|
||||
for ( int i = 0; i < realProps.Length; ++i )
|
||||
{
|
||||
object obj = realProps[i].GetValue( realObjs[i], null );
|
||||
|
||||
if( !( obj is IConvertible ) )
|
||||
return "Property is not IConvertable.";
|
||||
|
||||
try
|
||||
{
|
||||
|
||||
long v = (long)Convert.ChangeType( obj, TypeCode.Int64 );
|
||||
v += realValues[i];
|
||||
|
||||
realProps[i].SetValue( realObjs[i], Convert.ChangeType( v, realProps[i].PropertyType ), null );
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "Value could not be converted";
|
||||
}
|
||||
}
|
||||
|
||||
if ( realProps.Length == 1 )
|
||||
{
|
||||
if ( positive )
|
||||
return "The property has been increased.";
|
||||
|
||||
return "The property has been decreased.";
|
||||
}
|
||||
|
||||
if ( positive && negative )
|
||||
return "The properties have been changed.";
|
||||
|
||||
if ( positive )
|
||||
return "The properties have been increased.";
|
||||
|
||||
return "The properties have been decreased.";
|
||||
}
|
||||
|
||||
private static string InternalGetValue( object o, PropertyInfo p )
|
||||
{
|
||||
return InternalGetValue( o, p, null );
|
||||
}
|
||||
|
||||
private static string InternalGetValue( object o, PropertyInfo p, PropertyInfo[] chain )
|
||||
{
|
||||
Type type = p.PropertyType;
|
||||
|
||||
object value = p.GetValue( o, null );
|
||||
string toString;
|
||||
|
||||
if ( value == null )
|
||||
toString = "null";
|
||||
else if ( IsNumeric( type ) )
|
||||
toString = String.Format( "{0} (0x{0:X})", value );
|
||||
else if ( IsChar( type ) )
|
||||
toString = String.Format( "'{0}' ({1} [0x{1:X}])", value, (int) value );
|
||||
else if ( IsString( type ) )
|
||||
toString = ( (string) value == "null" ? @"@""null""" : String.Format( "\"{0}\"", value ) );
|
||||
else
|
||||
toString = value.ToString();
|
||||
|
||||
if ( chain == null )
|
||||
return String.Format( "{0} = {1}", p.Name, toString );
|
||||
|
||||
string[] concat = new string[chain.Length*2+1];
|
||||
|
||||
for ( int i = 0; i < chain.Length; ++i )
|
||||
{
|
||||
concat[(i*2)+0] = chain[i].Name;
|
||||
concat[(i*2)+1] = ( i < (chain.Length - 1) ) ? "." : " = ";
|
||||
}
|
||||
|
||||
concat[concat.Length-1] = toString;
|
||||
|
||||
return String.Concat( concat );
|
||||
}
|
||||
|
||||
public static string SetValue( Mobile from, object o, string name, string value )
|
||||
{
|
||||
object logObject = o;
|
||||
|
||||
string failReason = "";
|
||||
PropertyInfo p = GetPropertyInfo( from, ref o, name, PropertyAccess.Write, ref failReason );
|
||||
|
||||
if ( p == null )
|
||||
return failReason;
|
||||
|
||||
return InternalSetValue( from, logObject, o, p, name, value, true );
|
||||
}
|
||||
|
||||
private static Type typeofSerial = typeof( Serial );
|
||||
|
||||
private static bool IsSerial( Type t )
|
||||
{
|
||||
return ( t == typeofSerial );
|
||||
}
|
||||
|
||||
private static Type typeofType = typeof( Type );
|
||||
|
||||
private static bool IsType( Type t )
|
||||
{
|
||||
return ( t == typeofType );
|
||||
}
|
||||
|
||||
private static Type typeofChar = typeof( Char );
|
||||
|
||||
private static bool IsChar( Type t )
|
||||
{
|
||||
return ( t == typeofChar );
|
||||
}
|
||||
|
||||
private static Type typeofString = typeof( String );
|
||||
|
||||
private static bool IsString( Type t )
|
||||
{
|
||||
return ( t == typeofString );
|
||||
}
|
||||
|
||||
private static bool IsEnum( Type t )
|
||||
{
|
||||
return t.IsEnum;
|
||||
}
|
||||
|
||||
private static Type typeofTimeSpan = typeof( TimeSpan );
|
||||
private static Type typeofParsable = typeof( ParsableAttribute );
|
||||
|
||||
private static bool IsParsable( Type t )
|
||||
{
|
||||
return ( t == typeofTimeSpan || t.IsDefined( typeofParsable, false ) );
|
||||
}
|
||||
|
||||
private static Type[] m_ParseTypes = new Type[]{ typeof( string ) };
|
||||
private static object[] m_ParseParams = new object[1];
|
||||
|
||||
private static object Parse( object o, Type t, string value )
|
||||
{
|
||||
MethodInfo method = t.GetMethod( "Parse", m_ParseTypes );
|
||||
|
||||
m_ParseParams[0] = value;
|
||||
|
||||
return method.Invoke( o, m_ParseParams );
|
||||
}
|
||||
|
||||
private static Type[] m_NumericTypes = new Type[]
|
||||
{
|
||||
typeof( Byte ), typeof( SByte ),
|
||||
typeof( Int16 ), typeof( UInt16 ),
|
||||
typeof( Int32 ), typeof( UInt32 ),
|
||||
typeof( Int64 ), typeof( UInt64 )
|
||||
};
|
||||
|
||||
private static bool IsNumeric( Type t )
|
||||
{
|
||||
return ( Array.IndexOf( m_NumericTypes, t ) >= 0 );
|
||||
}
|
||||
|
||||
public static string ConstructFromString( Type type, object obj, string value, ref object constructed )
|
||||
{
|
||||
object toSet;
|
||||
bool isSerial = IsSerial( type );
|
||||
|
||||
if ( isSerial ) // mutate into int32
|
||||
type = m_NumericTypes[4];
|
||||
|
||||
if ( value == "(-null-)" && !type.IsValueType )
|
||||
value = null;
|
||||
|
||||
if ( IsEnum( type ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Enum.Parse( type, value, true );
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not a valid enumeration member.";
|
||||
}
|
||||
}
|
||||
else if ( IsType( type ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = ScriptCompiler.FindTypeByName( value );
|
||||
|
||||
if ( toSet == null )
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "No type with that name was found.";
|
||||
}
|
||||
}
|
||||
else if ( IsParsable( type ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Parse( obj, type, value );
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else if ( value == null )
|
||||
{
|
||||
toSet = null;
|
||||
}
|
||||
else if ( value.StartsWith( "0x" ) && IsNumeric( type ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Convert.ChangeType( Convert.ToUInt64( value.Substring( 2 ), 16 ), type );
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
toSet = Convert.ChangeType( value, type );
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "That is not properly formatted.";
|
||||
}
|
||||
}
|
||||
|
||||
if ( isSerial ) // mutate back
|
||||
toSet = (Serial)((Int32)toSet);
|
||||
|
||||
constructed = toSet;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static string SetDirect( Mobile from, object logObject, object obj, PropertyInfo prop, string givenName, object toSet, bool shouldLog )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( toSet is AccessLevel )
|
||||
{
|
||||
AccessLevel newLevel = (AccessLevel) toSet;
|
||||
AccessLevel reqLevel = AccessLevel.Administrator;
|
||||
|
||||
if ( newLevel == AccessLevel.Administrator )
|
||||
reqLevel = AccessLevel.Developer;
|
||||
else if ( newLevel >= AccessLevel.Developer )
|
||||
reqLevel = AccessLevel.Owner;
|
||||
|
||||
if ( from.AccessLevel < reqLevel )
|
||||
return "You do not have access to that level.";
|
||||
}
|
||||
|
||||
if ( shouldLog )
|
||||
CommandLogging.LogChangeProperty( from, logObject, givenName, toSet == null ? "(-null-)" : toSet.ToString() );
|
||||
|
||||
prop.SetValue( obj, toSet, null );
|
||||
return "Property has been set.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "An exception was caught, the property may not be set.";
|
||||
}
|
||||
}
|
||||
|
||||
public static string SetDirect( object obj, PropertyInfo prop, object toSet )
|
||||
{
|
||||
try
|
||||
{
|
||||
if ( toSet is AccessLevel )
|
||||
{
|
||||
return "You do not have access to that level.";
|
||||
}
|
||||
|
||||
prop.SetValue( obj, toSet, null );
|
||||
return "Property has been set.";
|
||||
}
|
||||
catch
|
||||
{
|
||||
return "An exception was caught, the property may not be set.";
|
||||
}
|
||||
}
|
||||
|
||||
public static string InternalSetValue( Mobile from, object logobj, object o, PropertyInfo p, string pname, string value, bool shouldLog )
|
||||
{
|
||||
object toSet = null;
|
||||
string result = ConstructFromString( p.PropertyType, o, value, ref toSet );
|
||||
|
||||
if ( result != null )
|
||||
return result;
|
||||
|
||||
return SetDirect( from, logobj, o, p, pname, toSet, shouldLog );
|
||||
}
|
||||
|
||||
public static string InternalSetValue( object o, PropertyInfo p, string value )
|
||||
{
|
||||
object toSet = null;
|
||||
string result = ConstructFromString( p.PropertyType, o, value, ref toSet );
|
||||
|
||||
if ( result != null )
|
||||
return result;
|
||||
|
||||
return SetDirect( o, p, toSet );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public abstract class PropertyException : ApplicationException
|
||||
{
|
||||
protected Property m_Property;
|
||||
|
||||
public Property Property
|
||||
{
|
||||
get { return m_Property; }
|
||||
}
|
||||
|
||||
public PropertyException( Property property, string message )
|
||||
: base( message )
|
||||
{
|
||||
m_Property = property;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class BindingException : PropertyException
|
||||
{
|
||||
public BindingException( Property property, string message )
|
||||
: base( property, message )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class NotYetBoundException : BindingException
|
||||
{
|
||||
public NotYetBoundException( Property property )
|
||||
: base( property, String.Format( "Property has not yet been bound." ) )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class AlreadyBoundException : BindingException
|
||||
{
|
||||
public AlreadyBoundException( Property property )
|
||||
: base( property, String.Format( "Property has already been bound." ) )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class UnknownPropertyException : BindingException
|
||||
{
|
||||
public UnknownPropertyException( Property property, string current )
|
||||
: base( property, String.Format( "Property '{0}' not found.", current ) )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReadOnlyException : BindingException
|
||||
{
|
||||
public ReadOnlyException( Property property )
|
||||
: base( property, "Property is read-only." )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WriteOnlyException : BindingException
|
||||
{
|
||||
public WriteOnlyException( Property property )
|
||||
: base( property, "Property is write-only." )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class AccessException : PropertyException
|
||||
{
|
||||
public AccessException( Property property, string message )
|
||||
: base( property, message )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class InternalAccessException : AccessException
|
||||
{
|
||||
public InternalAccessException( Property property )
|
||||
: base( property, "Property is internal." )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class ClearanceException : AccessException
|
||||
{
|
||||
protected AccessLevel m_PlayerAccess;
|
||||
protected AccessLevel m_NeededAccess;
|
||||
|
||||
public AccessLevel PlayerAccess
|
||||
{
|
||||
get { return m_PlayerAccess; }
|
||||
}
|
||||
|
||||
public AccessLevel NeededAccess
|
||||
{
|
||||
get { return m_NeededAccess; }
|
||||
}
|
||||
|
||||
public ClearanceException( Property property, AccessLevel playerAccess, AccessLevel neededAccess, string accessType )
|
||||
: base( property, string.Format(
|
||||
"You must be at least {0} to {1} this property.",
|
||||
Mobile.GetAccessLevelName( neededAccess ),
|
||||
accessType
|
||||
) )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class ReadAccessException : ClearanceException
|
||||
{
|
||||
public ReadAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess )
|
||||
: base( property, playerAccess, neededAccess, "read" )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class WriteAccessException : ClearanceException
|
||||
{
|
||||
public WriteAccessException( Property property, AccessLevel playerAccess, AccessLevel neededAccess )
|
||||
: base( property, playerAccess, neededAccess, "write" )
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public sealed class Property
|
||||
{
|
||||
private string m_Binding;
|
||||
|
||||
private PropertyInfo[] m_Chain;
|
||||
private PropertyAccess m_Access;
|
||||
|
||||
public string Binding
|
||||
{
|
||||
get { return m_Binding; }
|
||||
}
|
||||
|
||||
public bool IsBound
|
||||
{
|
||||
get { return ( m_Chain != null ); }
|
||||
}
|
||||
|
||||
public PropertyAccess Access
|
||||
{
|
||||
get { return m_Access; }
|
||||
}
|
||||
|
||||
public PropertyInfo[] Chain
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( !IsBound )
|
||||
throw new NotYetBoundException( this );
|
||||
|
||||
return m_Chain;
|
||||
}
|
||||
}
|
||||
|
||||
public Type Type
|
||||
{
|
||||
get
|
||||
{
|
||||
if ( !IsBound )
|
||||
throw new NotYetBoundException( this );
|
||||
|
||||
return m_Chain[m_Chain.Length - 1].PropertyType;
|
||||
}
|
||||
}
|
||||
|
||||
public bool CheckAccess( Mobile from )
|
||||
{
|
||||
if ( !IsBound )
|
||||
throw new NotYetBoundException( this );
|
||||
|
||||
for ( int i = 0; i < m_Chain.Length; ++i )
|
||||
{
|
||||
PropertyInfo prop = m_Chain[i];
|
||||
|
||||
bool isFinal = ( i == ( m_Chain.Length - 1 ) );
|
||||
|
||||
PropertyAccess access = m_Access;
|
||||
|
||||
if ( !isFinal )
|
||||
access |= PropertyAccess.Read;
|
||||
|
||||
CPA security = Properties.GetCPA( prop );
|
||||
|
||||
if ( security == null )
|
||||
throw new InternalAccessException( this );
|
||||
|
||||
if ( ( access & PropertyAccess.Read ) != 0 && from.AccessLevel < security.ReadLevel )
|
||||
throw new ReadAccessException( this, from.AccessLevel, security.ReadLevel );
|
||||
|
||||
if ( ( access & PropertyAccess.Write ) != 0 && (from.AccessLevel < security.WriteLevel || security.ReadOnly) )
|
||||
throw new WriteAccessException( this, from.AccessLevel, security.ReadLevel );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public void BindTo( Type objectType, PropertyAccess desiredAccess )
|
||||
{
|
||||
if ( IsBound )
|
||||
throw new AlreadyBoundException( this );
|
||||
|
||||
string[] split = m_Binding.Split( '.' );
|
||||
|
||||
PropertyInfo[] chain = new PropertyInfo[split.Length];
|
||||
|
||||
for ( int i = 0; i < split.Length; ++i )
|
||||
{
|
||||
bool isFinal = ( i == ( chain.Length - 1 ) );
|
||||
|
||||
chain[i] = objectType.GetProperty( split[i], BindingFlags.Instance | BindingFlags.Public | BindingFlags.IgnoreCase );
|
||||
|
||||
if ( chain[i] == null )
|
||||
throw new UnknownPropertyException( this, split[i] );
|
||||
|
||||
objectType = chain[i].PropertyType;
|
||||
|
||||
PropertyAccess access = desiredAccess;
|
||||
|
||||
if ( !isFinal )
|
||||
access |= PropertyAccess.Read;
|
||||
|
||||
if ( ( access & PropertyAccess.Read ) != 0 && !chain[i].CanRead )
|
||||
throw new WriteOnlyException( this );
|
||||
|
||||
if ( ( access & PropertyAccess.Write ) != 0 && !chain[i].CanWrite )
|
||||
throw new ReadOnlyException( this );
|
||||
}
|
||||
|
||||
m_Access = desiredAccess;
|
||||
m_Chain = chain;
|
||||
}
|
||||
|
||||
public Property( string binding )
|
||||
{
|
||||
m_Binding = binding;
|
||||
}
|
||||
|
||||
public Property( PropertyInfo[] chain )
|
||||
{
|
||||
m_Chain = chain;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if ( !IsBound )
|
||||
return m_Binding;
|
||||
|
||||
string[] toJoin = new string[m_Chain.Length];
|
||||
|
||||
for ( int i = 0; i < toJoin.Length; ++i )
|
||||
toJoin[i] = m_Chain[i].Name;
|
||||
|
||||
return string.Join( ".", toJoin );
|
||||
}
|
||||
|
||||
public static Property Parse( Type type, string binding, PropertyAccess access )
|
||||
{
|
||||
Property prop = new Property( binding );
|
||||
|
||||
prop.BindTo( type, access );
|
||||
|
||||
return prop;
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue