fix: Consolidates properties code (#785)
* Consolidates the property logic between properties and add. * Fixes a bug with setting properties
This commit is contained in:
parent
ec785e6f07
commit
bba5346a92
4 changed files with 123 additions and 168 deletions
|
|
@ -76,67 +76,57 @@ namespace Server.Commands
|
|||
CommandLogging.Enabled = false;
|
||||
}
|
||||
|
||||
List<object> usedList;
|
||||
var propertyChains = new Dictionary<Type, PropertyInfo[]>();
|
||||
var usedList = new List<object>(list.Count);
|
||||
|
||||
if (Utility.InsensitiveCompare(bc.Object, "Current") == 0)
|
||||
for (var j = 0; j < list.Count; ++j)
|
||||
{
|
||||
usedList = list;
|
||||
}
|
||||
else
|
||||
{
|
||||
var propertyChains = new Dictionary<Type, PropertyInfo[]>();
|
||||
var obj = list[j];
|
||||
|
||||
usedList = new List<object>(list.Count);
|
||||
|
||||
for (var j = 0; j < list.Count; ++j)
|
||||
if (obj == null)
|
||||
{
|
||||
var obj = list[j];
|
||||
continue;
|
||||
}
|
||||
|
||||
if (obj == null)
|
||||
var type = obj.GetType();
|
||||
var failReason = "";
|
||||
|
||||
if (!propertyChains.TryGetValue(type, out var chain))
|
||||
{
|
||||
propertyChains[type] = chain = Properties.GetPropertyInfoChain(
|
||||
e.Mobile,
|
||||
type,
|
||||
bc.Object,
|
||||
PropertyAccess.Read,
|
||||
out failReason
|
||||
);
|
||||
}
|
||||
|
||||
if (chain == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endProp = Properties.GetPropertyInfo(ref obj, chain, out failReason);
|
||||
|
||||
if (endProp == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
obj = endProp.GetValue(obj, null);
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var type = obj.GetType();
|
||||
var failReason = "";
|
||||
|
||||
if (!propertyChains.TryGetValue(type, out var chain))
|
||||
{
|
||||
propertyChains[type] = chain = Properties.GetPropertyInfoChain(
|
||||
e.Mobile,
|
||||
type,
|
||||
bc.Object,
|
||||
PropertyAccess.Read,
|
||||
ref failReason
|
||||
);
|
||||
}
|
||||
|
||||
if (chain == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var endProp = Properties.GetPropertyInfo(ref obj, chain, ref failReason);
|
||||
|
||||
if (endProp == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
obj = endProp.GetValue(obj, null);
|
||||
|
||||
if (obj != null)
|
||||
{
|
||||
usedList.Add(obj);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
usedList.Add(obj);
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
|
||||
command.ExecuteList(eventArgs[i], usedList);
|
||||
|
|
|
|||
|
|
@ -115,13 +115,12 @@ namespace Server.Commands.Generic
|
|||
|
||||
if (obj != null)
|
||||
{
|
||||
string failReason = null;
|
||||
var chain = Properties.GetPropertyInfoChain(
|
||||
m_From,
|
||||
obj.GetType(),
|
||||
m_Columns[i],
|
||||
PropertyAccess.Read,
|
||||
ref failReason
|
||||
out _
|
||||
);
|
||||
|
||||
if (chain?.Length > 0)
|
||||
|
|
@ -187,14 +186,13 @@ namespace Server.Commands.Generic
|
|||
var src = obj;
|
||||
|
||||
string value;
|
||||
var failReason = "";
|
||||
|
||||
var chain = Properties.GetPropertyInfoChain(
|
||||
m_From,
|
||||
src.GetType(),
|
||||
m_Columns[j],
|
||||
PropertyAccess.Read,
|
||||
ref failReason
|
||||
out _
|
||||
);
|
||||
|
||||
if (chain == null || chain.Length == 0)
|
||||
|
|
@ -203,7 +201,7 @@ namespace Server.Commands.Generic
|
|||
}
|
||||
else
|
||||
{
|
||||
var p = Properties.GetPropertyInfo(ref src, chain, ref failReason);
|
||||
var p = Properties.GetPropertyInfo(ref src, chain, out _);
|
||||
|
||||
if (p == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -149,46 +149,16 @@ namespace Server.Commands
|
|||
|
||||
for (var i = 0; i < realProps.Length; ++i)
|
||||
{
|
||||
PropertyInfo thisProp = null;
|
||||
|
||||
var propName = props[i, 0];
|
||||
var thisProp = Properties.GetPropertyInfoByName(from, allProps, propName, PropertyAccess.Write, out var failReason);
|
||||
|
||||
for (var j = 0; thisProp == null && j < allProps.Length; ++j)
|
||||
if (failReason == null)
|
||||
{
|
||||
if (propName.InsensitiveEquals(allProps[j].Name))
|
||||
{
|
||||
thisProp = allProps[j];
|
||||
}
|
||||
}
|
||||
|
||||
if (thisProp == null)
|
||||
{
|
||||
from.SendMessage("Property not found: {0}", propName);
|
||||
realProps[i] = thisProp;
|
||||
}
|
||||
else
|
||||
{
|
||||
var attr = GetCPA(thisProp);
|
||||
|
||||
if (attr == null)
|
||||
{
|
||||
from.SendMessage("Property ({0}) not found.", propName);
|
||||
}
|
||||
else if (from.AccessLevel < attr.WriteLevel)
|
||||
{
|
||||
from.SendMessage(
|
||||
"Setting this property ({0}) requires at least {1} access level.",
|
||||
propName,
|
||||
Mobile.GetAccessLevelName(attr.WriteLevel)
|
||||
);
|
||||
}
|
||||
else if (!thisProp.CanWrite || attr.ReadOnly)
|
||||
{
|
||||
from.SendMessage("Property ({0}) is read only.", propName);
|
||||
}
|
||||
else
|
||||
{
|
||||
realProps[i] = thisProp;
|
||||
}
|
||||
from.SendMessage(failReason);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,13 +55,69 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
|
||||
private static bool CIEqual(string l, string r) => l.InsensitiveEquals(r);
|
||||
public static PropertyInfo GetPropertyInfoByName(
|
||||
Mobile from, PropertyInfo[] props, string propertyName, PropertyAccess access, out string failReason
|
||||
)
|
||||
{
|
||||
for (var i = 0; i < props.Length; i++)
|
||||
{
|
||||
var p = props[i];
|
||||
|
||||
if (!p.Name.InsensitiveEquals(propertyName))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var attr = GetCPA(p);
|
||||
|
||||
if (attr == null)
|
||||
{
|
||||
failReason = $"Property '${propertyName}' not found.";
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Read) != 0 && from.AccessLevel < attr.ReadLevel)
|
||||
{
|
||||
failReason =
|
||||
$"You must be at least {Mobile.GetAccessLevelName(attr.ReadLevel)} to get the property '{propertyName}'.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Write) != 0 && from.AccessLevel < attr.WriteLevel)
|
||||
{
|
||||
failReason =
|
||||
$"You must be at least {Mobile.GetAccessLevelName(attr.WriteLevel)} to set the property '{propertyName}'.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Read) != 0 && !p.CanRead)
|
||||
{
|
||||
failReason = $"Property '{propertyName}' is write only.";
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Write) != 0 && (!p.CanWrite && !attr.CanModify || attr.ReadOnly))
|
||||
{
|
||||
failReason = $"Property '{propertyName}' is read only.";
|
||||
return null;
|
||||
}
|
||||
|
||||
failReason = null;
|
||||
return p;
|
||||
}
|
||||
|
||||
failReason = null;
|
||||
return null;
|
||||
}
|
||||
|
||||
public static PropertyInfo[] GetPropertyInfoChain(
|
||||
Mobile from, Type type, string propertyString,
|
||||
PropertyAccess endAccess, ref string failReason
|
||||
PropertyAccess access, out string failReason
|
||||
)
|
||||
{
|
||||
failReason = null;
|
||||
var split = propertyString.Split('.');
|
||||
|
||||
if (split.Length == 0)
|
||||
|
|
@ -74,76 +130,18 @@ namespace Server.Commands
|
|||
for (var i = 0; i < info.Length; ++i)
|
||||
{
|
||||
var propertyName = split[i];
|
||||
|
||||
if (CIEqual(propertyName, "current"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
var props = type.GetProperties(BindingFlags.Static | BindingFlags.Instance | BindingFlags.Public);
|
||||
|
||||
var isFinal = i == info.Length - 1;
|
||||
var p = GetPropertyInfoByName(from, props, propertyName, access, out failReason);
|
||||
|
||||
var access = endAccess;
|
||||
|
||||
if (!isFinal)
|
||||
if (p == null)
|
||||
{
|
||||
access |= PropertyAccess.Read;
|
||||
}
|
||||
|
||||
for (var j = 0; j < props.Length; ++j)
|
||||
{
|
||||
var p = props[j];
|
||||
|
||||
if (CIEqual(p.Name, propertyName))
|
||||
{
|
||||
var attr = GetCPA(p);
|
||||
|
||||
if (attr == null)
|
||||
{
|
||||
failReason = $"Property '{propertyName}' not found.";
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Read) != 0 && from.AccessLevel < attr.ReadLevel)
|
||||
{
|
||||
failReason =
|
||||
$"You must be at least {Mobile.GetAccessLevelName(attr.ReadLevel)} to get the property '{propertyName}'.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Write) != 0 && from.AccessLevel < attr.WriteLevel)
|
||||
{
|
||||
failReason =
|
||||
$"You must be at least {Mobile.GetAccessLevelName(attr.WriteLevel)} to set the property '{propertyName}'.";
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Read) != 0 && !p.CanRead)
|
||||
{
|
||||
failReason = $"Property '{propertyName}' is write only.";
|
||||
return null;
|
||||
}
|
||||
|
||||
if ((access & PropertyAccess.Write) != 0 && (!p.CanWrite || attr.ReadOnly) && isFinal)
|
||||
{
|
||||
failReason = $"Property '{propertyName}' is read only.";
|
||||
return null;
|
||||
}
|
||||
|
||||
info[i] = p;
|
||||
type = p.PropertyType;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (info[i] == null)
|
||||
{
|
||||
failReason = $"Property '{propertyName}' not found.";
|
||||
failReason ??= $"Property '{propertyName}' not found.";
|
||||
return null;
|
||||
}
|
||||
|
||||
info[i] = p;
|
||||
type = p.PropertyType;
|
||||
}
|
||||
|
||||
return info;
|
||||
|
|
@ -151,15 +149,15 @@ namespace Server.Commands
|
|||
|
||||
public static PropertyInfo GetPropertyInfo(
|
||||
Mobile from, ref object obj, string propertyName, PropertyAccess access,
|
||||
ref string failReason
|
||||
out string failReason
|
||||
)
|
||||
{
|
||||
var chain = GetPropertyInfoChain(from, obj.GetType(), propertyName, access, ref failReason);
|
||||
var chain = GetPropertyInfoChain(from, obj.GetType(), propertyName, access, out failReason);
|
||||
|
||||
return chain == null ? null : GetPropertyInfo(ref obj, chain, ref failReason);
|
||||
return chain == null ? null : GetPropertyInfo(ref obj, chain, out failReason);
|
||||
}
|
||||
|
||||
public static PropertyInfo GetPropertyInfo(ref object obj, PropertyInfo[] chain, ref string failReason)
|
||||
public static PropertyInfo GetPropertyInfo(ref object obj, PropertyInfo[] chain, out string failReason)
|
||||
{
|
||||
if (chain == null || chain.Length == 0)
|
||||
{
|
||||
|
|
@ -183,6 +181,7 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
|
||||
failReason = null;
|
||||
return chain[^1];
|
||||
}
|
||||
|
||||
|
|
@ -190,14 +189,14 @@ namespace Server.Commands
|
|||
{
|
||||
var failReason = "";
|
||||
|
||||
var chain = GetPropertyInfoChain(from, o.GetType(), name, PropertyAccess.Read, ref failReason);
|
||||
var chain = GetPropertyInfoChain(from, o.GetType(), name, PropertyAccess.Read, out failReason);
|
||||
|
||||
if (chain == null || chain.Length == 0)
|
||||
{
|
||||
return failReason;
|
||||
}
|
||||
|
||||
var p = GetPropertyInfo(ref o, chain, ref failReason);
|
||||
var p = GetPropertyInfo(ref o, chain, out failReason);
|
||||
|
||||
return p == null ? failReason : InternalGetValue(o, p, chain);
|
||||
}
|
||||
|
|
@ -246,9 +245,8 @@ namespace Server.Commands
|
|||
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);
|
||||
realProps[i] = GetPropertyInfo(from, ref realObjs[i], name, PropertyAccess.ReadWrite, out var failReason);
|
||||
|
||||
if (failReason != null)
|
||||
{
|
||||
|
|
@ -353,8 +351,7 @@ namespace Server.Commands
|
|||
{
|
||||
var logObject = o;
|
||||
|
||||
var failReason = "";
|
||||
var p = GetPropertyInfo(from, ref o, name, PropertyAccess.Write, ref failReason);
|
||||
var p = GetPropertyInfo(from, ref o, name, PropertyAccess.Write, out var failReason);
|
||||
|
||||
return p == null ? failReason : InternalSetValue(from, logObject, o, p, name, value, true);
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue