fixes TypeCache lookup speed and errors (#95)
This commit is contained in:
parent
e97d2cb131
commit
f8f372ccb9
26 changed files with 101 additions and 109 deletions
|
|
@ -101,7 +101,7 @@ namespace Server.Commands
|
|||
break;
|
||||
}
|
||||
|
||||
Type type = AssemblyHandler.FindTypeByName(name);
|
||||
Type type = AssemblyHandler.FindFirstTypeForName(name);
|
||||
|
||||
if (!IsEntity(type))
|
||||
{
|
||||
|
|
@ -241,7 +241,7 @@ namespace Server.Commands
|
|||
try
|
||||
{
|
||||
if (IsEnum(type)) return Enum.Parse(type, value, true);
|
||||
if (IsType(type)) return AssemblyHandler.FindTypeByName(value);
|
||||
if (IsType(type)) return AssemblyHandler.FindFirstTypeForName(value);
|
||||
if (IsParsable(type)) return ParseParsable(type, value);
|
||||
object obj = value;
|
||||
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,7 @@ namespace Server.Commands
|
|||
|
||||
int indexOf = line.IndexOf(' ');
|
||||
|
||||
list.m_Type = AssemblyHandler.FindTypeByName(line.Substring(0, indexOf++), true);
|
||||
list.m_Type = AssemblyHandler.FindFirstTypeForName(line.Substring(0, indexOf++), true);
|
||||
|
||||
if (list.m_Type == null)
|
||||
throw new ArgumentException($"Type not found for header: '{line}'");
|
||||
|
|
|
|||
|
|
@ -1012,7 +1012,7 @@ namespace Server.Commands
|
|||
|
||||
int indexOf = line.IndexOf(' ');
|
||||
|
||||
list.m_Type = AssemblyHandler.FindTypeByName(line.Substring(0, indexOf++), true);
|
||||
list.m_Type = AssemblyHandler.FindFirstTypeForName(line.Substring(0, indexOf++), true);
|
||||
|
||||
if (list.m_Type == null)
|
||||
throw new ArgumentException($"Type not found for header: '{line}'");
|
||||
|
|
|
|||
|
|
@ -316,7 +316,7 @@ namespace Server.Commands
|
|||
|
||||
for (int i = 0; i < split.Length; ++i)
|
||||
{
|
||||
Type type = AssemblyHandler.FindTypeByName(split[i].Trim());
|
||||
Type type = AssemblyHandler.FindFirstTypeForName(split[i].Trim());
|
||||
|
||||
if (type == null)
|
||||
Console.WriteLine("Match type not found ('{0}')", split[i].Trim());
|
||||
|
|
|
|||
|
|
@ -444,7 +444,7 @@ namespace Server.Commands.Generic
|
|||
{
|
||||
if (e.Length >= 1)
|
||||
{
|
||||
Type t = AssemblyHandler.FindTypeByName(e.GetString(0));
|
||||
Type t = AssemblyHandler.FindFirstTypeForName(e.GetString(0));
|
||||
|
||||
if (t == null)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ namespace Server.Commands.Generic
|
|||
|
||||
int index = 0;
|
||||
|
||||
Type objectType = AssemblyHandler.FindTypeByName(args[offset + index], true);
|
||||
Type objectType = AssemblyHandler.FindFirstTypeForName(args[offset + index], true);
|
||||
|
||||
if (objectType == null)
|
||||
throw new Exception($"No type with that name ({args[offset + index]}) was found.");
|
||||
|
|
|
|||
|
|
@ -282,7 +282,7 @@ namespace Server.Commands
|
|||
int count = bin.ReadInt32();
|
||||
|
||||
for (int i = 0; i < count; ++i)
|
||||
types.Add(AssemblyHandler.FindTypeByFullName(bin.ReadString()));
|
||||
types.Add(AssemblyHandler.FindFirstTypeForName(bin.ReadString()));
|
||||
}
|
||||
|
||||
long total = 0;
|
||||
|
|
|
|||
|
|
@ -391,7 +391,7 @@ namespace Server.Commands
|
|||
else if (IsType(type))
|
||||
try
|
||||
{
|
||||
toSet = AssemblyHandler.FindTypeByName(value);
|
||||
toSet = AssemblyHandler.FindFirstTypeForName(value);
|
||||
|
||||
if (toSet == null)
|
||||
return "No type with that name was found.";
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ namespace Server.Engines.BulkOrders
|
|||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
ItemType = AssemblyHandler.FindTypeByFullName(type);
|
||||
ItemType = AssemblyHandler.FindFirstTypeForName(type);
|
||||
|
||||
AmountCur = reader.ReadEncodedInt();
|
||||
Number = reader.ReadEncodedInt();
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ namespace Server.Engines.BulkOrders
|
|||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
ItemType = AssemblyHandler.FindTypeByFullName(type);
|
||||
ItemType = AssemblyHandler.FindFirstTypeForName(type);
|
||||
|
||||
RequireExceptional = reader.ReadBool();
|
||||
|
||||
|
|
|
|||
|
|
@ -103,7 +103,7 @@ namespace Server.Engines.BulkOrders
|
|||
string type = reader.ReadString();
|
||||
|
||||
if ( type != null )
|
||||
realType = AssemblyHandler.FindTypeByFullName( type );
|
||||
realType = AssemblyHandler.FindFirstTypeForName( type );
|
||||
|
||||
Details = new SmallBulkEntry( realType, reader.ReadInt(), reader.ReadInt() );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -200,7 +200,7 @@ namespace Server.Engines.BulkOrders
|
|||
string type = reader.ReadString();
|
||||
|
||||
if (type != null)
|
||||
Type = AssemblyHandler.FindTypeByFullName(type);
|
||||
Type = AssemblyHandler.FindFirstTypeForName(type);
|
||||
|
||||
m_Number = reader.ReadInt();
|
||||
Graphic = reader.ReadInt();
|
||||
|
|
|
|||
|
|
@ -67,7 +67,7 @@ namespace Server.Engines.BulkOrders
|
|||
|
||||
if ( split.Length >= 2 )
|
||||
{
|
||||
Type type = AssemblyHandler.FindTypeByName( split[0] );
|
||||
Type type = AssemblyHandler.FindFirstTypeForName( split[0] );
|
||||
int graphic = Utility.ToInt32( split[split.Length - 1] );
|
||||
|
||||
if ( type != null && graphic > 0 )
|
||||
|
|
|
|||
|
|
@ -294,7 +294,7 @@ namespace Server.Engines.Doom
|
|||
if (TypeName == null)
|
||||
return;
|
||||
|
||||
Type type = AssemblyHandler.FindTypeByName(TypeName, true);
|
||||
Type type = AssemblyHandler.FindFirstTypeForName(TypeName, true);
|
||||
|
||||
if (type == null)
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,7 @@
|
|||
using Server.Utilities;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
|
||||
namespace Server.Factions
|
||||
|
|
@ -56,7 +57,7 @@ namespace Server.Factions
|
|||
{
|
||||
Assembly asm = asms[i];
|
||||
TypeCache tc = AssemblyHandler.GetTypeCache(asm);
|
||||
Type[] types = tc.Types;
|
||||
Type[] types = tc.Types.ToArray();
|
||||
|
||||
for (int j = 0; j < types.Length; ++j)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -88,7 +88,7 @@ namespace Server.Engines.MLQuests.Items
|
|||
string typeName = reader.ReadString();
|
||||
|
||||
if (typeName != null)
|
||||
m_QuestType = AssemblyHandler.FindTypeByFullName(typeName, false);
|
||||
m_QuestType = AssemblyHandler.FindFirstTypeForName(typeName, false);
|
||||
|
||||
Message = TextDefinition.Deserialize(reader);
|
||||
}
|
||||
|
|
@ -186,7 +186,7 @@ namespace Server.Engines.MLQuests.Items
|
|||
string typeName = reader.ReadString();
|
||||
|
||||
if (typeName != null)
|
||||
m_TicketType = AssemblyHandler.FindTypeByFullName(typeName, false);
|
||||
m_TicketType = AssemblyHandler.FindFirstTypeForName(typeName, false);
|
||||
|
||||
Message = TextDefinition.Deserialize(reader);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -48,7 +48,7 @@ namespace Server.Engines.MLQuests
|
|||
|
||||
string[] split = line.Split('\t');
|
||||
|
||||
Type type = AssemblyHandler.FindTypeByName(split[0]);
|
||||
Type type = AssemblyHandler.FindFirstTypeForName(split[0]);
|
||||
|
||||
if (type == null || !baseQuestType.IsAssignableFrom(type))
|
||||
{
|
||||
|
|
@ -77,7 +77,7 @@ namespace Server.Engines.MLQuests
|
|||
|
||||
for (int i = 1; i < split.Length; ++i)
|
||||
{
|
||||
Type questerType = AssemblyHandler.FindTypeByName(split[i]);
|
||||
Type questerType = AssemblyHandler.FindFirstTypeForName(split[i]);
|
||||
|
||||
if (questerType == null || !baseQuesterType.IsAssignableFrom(questerType))
|
||||
{
|
||||
|
|
@ -158,7 +158,7 @@ namespace Server.Engines.MLQuests
|
|||
return;
|
||||
}
|
||||
|
||||
Type index = AssemblyHandler.FindTypeByName(e.GetString(0));
|
||||
Type index = AssemblyHandler.FindFirstTypeForName(e.GetString(0));
|
||||
|
||||
if (index == null || !Quests.TryGetValue(index, out MLQuest quest))
|
||||
{
|
||||
|
|
@ -184,7 +184,7 @@ namespace Server.Engines.MLQuests
|
|||
return;
|
||||
}
|
||||
|
||||
Type index = AssemblyHandler.FindTypeByName(e.GetString(0));
|
||||
Type index = AssemblyHandler.FindFirstTypeForName(e.GetString(0));
|
||||
|
||||
if (index == null || !Quests.TryGetValue(index, out MLQuest quest))
|
||||
{
|
||||
|
|
@ -636,7 +636,7 @@ namespace Server.Engines.MLQuests
|
|||
if (typeName == null)
|
||||
return null; // not serialized
|
||||
|
||||
Type questType = AssemblyHandler.FindTypeByFullName(typeName);
|
||||
Type questType = AssemblyHandler.FindFirstTypeForName(typeName);
|
||||
|
||||
if (questType == null)
|
||||
return null; // no longer a type
|
||||
|
|
|
|||
|
|
@ -64,7 +64,7 @@ namespace Server.Engines.Quests
|
|||
if (fullName == null)
|
||||
return null;
|
||||
|
||||
return AssemblyHandler.FindTypeByFullName(fullName, false);
|
||||
return AssemblyHandler.FindFirstTypeForName(fullName, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,6 +4,6 @@ namespace Server.Mobiles
|
|||
{
|
||||
public class SpawnerType
|
||||
{
|
||||
public static Type GetType(string name) => AssemblyHandler.FindTypeByName(name);
|
||||
public static Type GetType(string name) => AssemblyHandler.FindFirstTypeForName(name);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Server.Network;
|
||||
using Server.Targeting;
|
||||
|
|
@ -136,11 +137,11 @@ namespace Server.Gumps
|
|||
|
||||
for (int i = 0; i < asms.Length; ++i)
|
||||
{
|
||||
types = AssemblyHandler.GetTypeCache(asms[i]).Types;
|
||||
types = AssemblyHandler.GetTypeCache(asms[i]).Types.ToArray();
|
||||
Match(match, types, results);
|
||||
}
|
||||
|
||||
types = AssemblyHandler.GetTypeCache(Core.Assembly).Types;
|
||||
types = AssemblyHandler.GetTypeCache(Core.Assembly).Types.ToArray();
|
||||
Match(match, types, results);
|
||||
|
||||
results.Sort(new TypeNameComparer());
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Server.Gumps
|
|||
Parent = parent;
|
||||
|
||||
if (xml.MoveToAttribute("type"))
|
||||
Type = AssemblyHandler.FindTypeByFullName(xml.Value, false);
|
||||
Type = AssemblyHandler.FindFirstTypeForName(xml.Value, false);
|
||||
|
||||
if (xml.MoveToAttribute("gfx"))
|
||||
ItemID = XmlConvert.ToInt32(xml.Value);
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ namespace Server.Items
|
|||
SaveFlag flags = (SaveFlag)reader.ReadEncodedInt();
|
||||
|
||||
if (GetSaveFlag(flags, SaveFlag.Type))
|
||||
Type = AssemblyHandler.FindTypeByFullName(reader.ReadString(), false);
|
||||
Type = AssemblyHandler.FindFirstTypeForName(reader.ReadString(), false);
|
||||
|
||||
if (GetSaveFlag(flags, SaveFlag.Name))
|
||||
Name = TextDefinition.Deserialize(reader);
|
||||
|
|
|
|||
|
|
@ -139,7 +139,7 @@ namespace Server.Spells
|
|||
{
|
||||
for (int i = 0; i < m_CircleNames.Length; ++i)
|
||||
{
|
||||
Type t = AssemblyHandler.FindTypeByFullName($"Server.Spells.{m_CircleNames[i]}.{name}");
|
||||
Type t = AssemblyHandler.FindFirstTypeForName($"Server.Spells.{m_CircleNames[i]}.{name}");
|
||||
|
||||
if (t?.IsSubclassOf(typeof(SpecialMove)) == false)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ using System.IO;
|
|||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Runtime.Loader;
|
||||
using System.Collections.Immutable;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
|
|
@ -62,28 +63,35 @@ namespace Server
|
|||
return m_TypeCaches[asm] = new TypeCache(asm);
|
||||
}
|
||||
|
||||
public static Type FindTypeByFullName(string fullName) => FindTypeByFullName(fullName, true);
|
||||
|
||||
public static Type FindTypeByFullName(string fullName, bool ignoreCase)
|
||||
public static Type FindFirstTypeForName(string name, bool ignoreCase = false, Func<Type, bool> predicate = null)
|
||||
{
|
||||
Type type = null;
|
||||
|
||||
for (int i = 0; type == null && i < Assemblies.Length; ++i)
|
||||
type = GetTypeCache(Assemblies[i]).GetTypeByFullName(fullName, ignoreCase);
|
||||
|
||||
return type ?? GetTypeCache(Core.Assembly).GetTypeByFullName(fullName, ignoreCase);
|
||||
var types = FindTypesByName(name, ignoreCase).ToList();
|
||||
if (types.Count == 0)
|
||||
return null;
|
||||
if (predicate != null)
|
||||
return types.FirstOrDefault(predicate);
|
||||
if (types.Count == 1)
|
||||
return types[0];
|
||||
// Try to find the closest match if there is no predicate.
|
||||
// Check for exact match of the FullName or Name
|
||||
// Then check for case-insensitive match of FullName or Name
|
||||
// Otherwise just return the first entry
|
||||
return (!ignoreCase ? types.FirstOrDefault(x => x.FullName == name || x.Name == name) : null)
|
||||
?? types.FirstOrDefault(x => StringComparer.OrdinalIgnoreCase.Equals(x.FullName, name) || StringComparer.OrdinalIgnoreCase.Equals(x.Name, name))
|
||||
?? types[0];
|
||||
}
|
||||
|
||||
public static Type FindTypeByName(string name) => FindTypeByName(name, true);
|
||||
|
||||
public static Type FindTypeByName(string name, bool ignoreCase)
|
||||
public static IEnumerable<Type> FindTypesByName(string name, bool ignoreCase = false)
|
||||
{
|
||||
Type type = null;
|
||||
|
||||
for (int i = 0; type == null && i < Assemblies.Length; ++i)
|
||||
type = GetTypeCache(Assemblies[i]).GetTypeByName(name, ignoreCase);
|
||||
|
||||
return type ?? GetTypeCache(Core.Assembly).GetTypeByName(name, ignoreCase);
|
||||
List<Type> types = new List<Type>();
|
||||
if(ignoreCase)
|
||||
name = name.ToLower();
|
||||
for (int i = 0; i < Assemblies.Length; i++)
|
||||
{
|
||||
types.AddRange(GetTypeCache(Assemblies[i])[name]);
|
||||
}
|
||||
if (types.Count == 0)
|
||||
types.AddRange(GetTypeCache(Core.Assembly)[name]);
|
||||
return types;
|
||||
}
|
||||
|
||||
public static string EnsureDirectory(string dir)
|
||||
|
|
@ -99,70 +107,52 @@ namespace Server
|
|||
|
||||
public class TypeCache
|
||||
{
|
||||
private Dictionary<string, int[]> m_NameMap = new Dictionary<string, int[]>();
|
||||
private Type[] m_Types;
|
||||
public IEnumerable<Type> Types { get => m_Types; }
|
||||
public IEnumerable<string> Names { get => m_NameMap.Keys; }
|
||||
|
||||
public IEnumerable<Type> this[string name]
|
||||
{
|
||||
get => m_NameMap.TryGetValue(name, out int[] value) ? value.Select(x => m_Types[x]) : new Type[0];
|
||||
}
|
||||
|
||||
public TypeCache(Assembly asm)
|
||||
{
|
||||
Types = asm?.GetTypes() ?? Type.EmptyTypes;
|
||||
|
||||
Names = new TypeTable(Types.Length);
|
||||
FullNames = new TypeTable(Types.Length);
|
||||
|
||||
Type typeofTypeAliasAttribute = typeof(TypeAliasAttribute);
|
||||
|
||||
for (int i = 0; i < Types.Length; ++i)
|
||||
m_Types = asm?.GetTypes() ?? Type.EmptyTypes;
|
||||
var nameMap = new Dictionary<string, HashSet<int>>();
|
||||
HashSet<int> refs;
|
||||
Action<int, string> addToRefs = (index, key) =>
|
||||
{
|
||||
Type type = Types[i];
|
||||
|
||||
Names.Add(type.Name, type);
|
||||
FullNames.Add(type.FullName, type);
|
||||
|
||||
if (type.IsDefined(typeofTypeAliasAttribute, false))
|
||||
if (nameMap.TryGetValue(key, out refs))
|
||||
refs.Add(index);
|
||||
else
|
||||
{
|
||||
object[] attrs = type.GetCustomAttributes(typeofTypeAliasAttribute, false);
|
||||
|
||||
if (attrs.Length > 0 && attrs[0] is TypeAliasAttribute attr)
|
||||
for (int j = 0; j < attr.Aliases.Length; ++j)
|
||||
FullNames.Add(attr.Aliases[j], type);
|
||||
refs = new HashSet<int>();
|
||||
refs.Add(index);
|
||||
nameMap.Add(key, refs);
|
||||
}
|
||||
};
|
||||
Type current;
|
||||
Type aliasType = typeof(TypeAliasAttribute);
|
||||
TypeAliasAttribute alias;
|
||||
for (int i = 0, j = 0; i < m_Types.Length; i++)
|
||||
{
|
||||
current = m_Types[i];
|
||||
addToRefs(i, current.Name);
|
||||
addToRefs(i, current.Name.ToLower());
|
||||
addToRefs(i, current.FullName);
|
||||
addToRefs(i, current.FullName.ToLower());
|
||||
alias = current.GetCustomAttribute(aliasType, false) as TypeAliasAttribute;
|
||||
if (alias != null)
|
||||
for (j = 0; j < alias.Aliases.Length; j++)
|
||||
{
|
||||
addToRefs(i, alias.Aliases[j]);
|
||||
addToRefs(i, alias.Aliases[j].ToLower());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Type[] Types{ get; }
|
||||
|
||||
public TypeTable Names{ get; }
|
||||
|
||||
public TypeTable FullNames{ get; }
|
||||
|
||||
public Type GetTypeByName(string name, bool ignoreCase) => Names.Get(name, ignoreCase);
|
||||
|
||||
public Type GetTypeByFullName(string fullName, bool ignoreCase) => FullNames.Get(fullName, ignoreCase);
|
||||
}
|
||||
|
||||
public class TypeTable
|
||||
{
|
||||
private Dictionary<string, Type> m_Sensitive, m_Insensitive;
|
||||
|
||||
public TypeTable(int capacity)
|
||||
{
|
||||
m_Sensitive = new Dictionary<string, Type>(capacity);
|
||||
m_Insensitive = new Dictionary<string, Type>(capacity, StringComparer.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
public void Add(string key, Type type)
|
||||
{
|
||||
m_Sensitive[key] = type;
|
||||
m_Insensitive[key] = type;
|
||||
}
|
||||
|
||||
public Type Get(string key, bool ignoreCase)
|
||||
{
|
||||
Type t;
|
||||
|
||||
if (ignoreCase)
|
||||
m_Insensitive.TryGetValue(key, out t);
|
||||
else
|
||||
m_Sensitive.TryGetValue(key, out t);
|
||||
|
||||
return t;
|
||||
foreach (var entry in nameMap)
|
||||
m_NameMap[entry.Key] = entry.Value.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -969,7 +969,7 @@ namespace Server
|
|||
Type type;
|
||||
try
|
||||
{
|
||||
type = AssemblyHandler.FindTypeByName(s, false);
|
||||
type = AssemblyHandler.FindFirstTypeForName(s, false);
|
||||
}
|
||||
catch
|
||||
{
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ namespace Server
|
|||
{
|
||||
string typeName = tdbReader.ReadString();
|
||||
|
||||
Type t = AssemblyHandler.FindTypeByFullName(typeName);
|
||||
Type t = AssemblyHandler.FindFirstTypeForName(typeName);
|
||||
|
||||
if (t == null)
|
||||
{
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue