fix: Consolidates properties code (#785)

* Consolidates the property logic between properties and add.
* Fixes a bug with setting properties
This commit is contained in:
Kamron Batman 2021-09-15 21:48:30 -07:00 • committed by GitHub
parent ec785e6f07
commit bba5346a92
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 123 additions and 168 deletions

View file

@ -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);

View file

@ -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)
{

View file

@ -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);
}
}
}

View file

@ -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);
}