core(fix): Fixes type aliasing, categorizations, and NPE (#444)
- [X] Fixes lookup of type aliases - [X] Fixes categorization - [X] Removes rebuild categorizations - [X] Fixes an NPE with DoHarmful and Combatant Closes #441
This commit is contained in:
parent
24ebdd0f90
commit
5d9ebf062f
17 changed files with 3821 additions and 4881 deletions
|
|
@ -261,8 +261,12 @@ namespace Server
|
|||
{
|
||||
for (var j = 0; j < alias.Aliases.Length; j++)
|
||||
{
|
||||
addToRefs(i, alias.Aliases[j], nameMap);
|
||||
addToRefs(i, alias.Aliases[j], nameMapInsensitive);
|
||||
var fullName = alias.Aliases[j];
|
||||
var name = fullName.Substring(fullName.LastIndexOf('.') + 1);
|
||||
addToRefs(i, fullName, nameMap);
|
||||
addToRefs(i, fullName.ToLower(), nameMapInsensitive);
|
||||
addToRefs(i, name, nameMap);
|
||||
addToRefs(i, name.ToLower(), nameMapInsensitive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,6 +28,13 @@ namespace Server.Json
|
|||
throw new JsonException("The JSON value could not be converted to System.Type");
|
||||
}
|
||||
|
||||
var typeName = reader.GetString();
|
||||
var type = AssemblyHandler.FindTypeByName(typeName);
|
||||
if (type == null)
|
||||
{
|
||||
Console.WriteLine("Invalid type {0} deserialized", typeName);
|
||||
}
|
||||
|
||||
return AssemblyHandler.FindTypeByName(reader.GetString());
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -950,7 +950,7 @@ namespace Server
|
|||
|
||||
if (m_Combatant == null)
|
||||
{
|
||||
m_NetState?.SendChangeCombatant(Serial.Zero);
|
||||
m_NetState.SendChangeCombatant(Serial.Zero);
|
||||
m_ExpireCombatant?.Stop();
|
||||
m_CombatTimer?.Stop();
|
||||
|
||||
|
|
@ -959,7 +959,7 @@ namespace Server
|
|||
}
|
||||
else
|
||||
{
|
||||
m_NetState?.SendChangeCombatant(m_Combatant.Serial);
|
||||
m_NetState.SendChangeCombatant(m_Combatant.Serial);
|
||||
m_ExpireCombatant ??= Timer.DelayCall(ExpireCombatantDelay, ExpireCombatant);
|
||||
m_ExpireCombatant.Start();
|
||||
|
||||
|
|
@ -968,8 +968,8 @@ namespace Server
|
|||
|
||||
if (CanBeHarmful(m_Combatant, false))
|
||||
{
|
||||
DoHarmful(m_Combatant);
|
||||
m_Combatant.PlaySound(m_Combatant.GetAngerSound());
|
||||
DoHarmful(m_Combatant); // due to reflection, might make m_Combatant null
|
||||
m_Combatant?.PlaySound(m_Combatant.GetAngerSound());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -8618,12 +8618,7 @@ namespace Server
|
|||
}
|
||||
}
|
||||
|
||||
public virtual void DoHarmful(Mobile target)
|
||||
{
|
||||
DoHarmful(target, false);
|
||||
}
|
||||
|
||||
public virtual void DoHarmful(Mobile target, bool indirect)
|
||||
public virtual void DoHarmful(Mobile target, bool indirect = false)
|
||||
{
|
||||
if (target == null || Deleted)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -17,7 +17,9 @@ using System;
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using Server.Items;
|
||||
using Server.Json;
|
||||
using Server.Utilities;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
|
|
@ -26,7 +28,7 @@ namespace Server.Commands
|
|||
public static CAGCategory Load()
|
||||
{
|
||||
var root = new CAGCategory("Add Menu");
|
||||
var path = Path.Combine(Core.BaseDirectory, "Data/objects.json");
|
||||
var path = Path.Combine(Core.BaseDirectory, "Data/categorization.json");
|
||||
|
||||
var list = JsonConfig.Deserialize<List<CAGJson>>(path);
|
||||
|
||||
|
|
@ -76,9 +78,61 @@ namespace Server.Commands
|
|||
parent.Nodes = new CAGNode[cag.Objects.Length];
|
||||
for (var i = 0; i < cag.Objects.Length; i++)
|
||||
{
|
||||
var obj = cag.Objects[i];
|
||||
obj.Parent = parent;
|
||||
parent.Nodes[i] = obj;
|
||||
var cagObj = cag.Objects[i];
|
||||
cagObj.Parent = parent;
|
||||
parent.Nodes[i] = cagObj;
|
||||
|
||||
// Set ItemID and Hue
|
||||
if (cagObj.Hue == null || cagObj.ItemID == null)
|
||||
{
|
||||
var type = cagObj.Type;
|
||||
|
||||
if (type.IsAssignableTo(typeof(Item)))
|
||||
{
|
||||
var item = cagObj.Type.CreateInstance<Item>();
|
||||
|
||||
if (cagObj.ItemID == null)
|
||||
{
|
||||
var itemID = item.ItemID;
|
||||
|
||||
if (item is BaseAddon addon && addon.Components.Count == 1)
|
||||
{
|
||||
itemID = addon.Components[0].ItemID;
|
||||
}
|
||||
|
||||
if (itemID > TileData.MaxItemValue)
|
||||
{
|
||||
itemID = 1;
|
||||
}
|
||||
|
||||
cagObj.ItemID = itemID;
|
||||
}
|
||||
|
||||
if (cagObj.Hue == null)
|
||||
{
|
||||
int hue = item.Hue & 0x7FFF;
|
||||
hue = (hue & 0x4000) != 0 ? 0 : hue;
|
||||
cagObj.Hue = hue == 0 ? null : hue;
|
||||
}
|
||||
|
||||
item.Delete();
|
||||
}
|
||||
|
||||
if (type.IsAssignableTo(typeof(Mobile)))
|
||||
{
|
||||
var m = cagObj.Type.CreateInstance<Mobile>();
|
||||
cagObj.ItemID ??= ShrinkTable.Lookup(m, 1);
|
||||
|
||||
if (cagObj.Hue == null)
|
||||
{
|
||||
int hue = m.Hue & 0x7FFF;
|
||||
hue = (hue & 0x4000) != 0 ? 0 : hue;
|
||||
cagObj.Hue = hue == 0 ? null : hue;
|
||||
}
|
||||
|
||||
m.Delete();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -86,10 +140,12 @@ namespace Server.Commands
|
|||
}
|
||||
}
|
||||
|
||||
public class CAGJson
|
||||
public record CAGJson
|
||||
{
|
||||
[JsonPropertyName("category")] public string Category { get; set; }
|
||||
[JsonPropertyName("category")]
|
||||
public string Category { get; init; }
|
||||
|
||||
[JsonPropertyName("objects")] public CAGObject[] Objects { get; set; }
|
||||
[JsonPropertyName("objects")]
|
||||
public CAGObject[] Objects { get; init; }
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,12 +21,15 @@ namespace Server.Commands
|
|||
{
|
||||
public class CAGObject : CAGNode
|
||||
{
|
||||
[JsonPropertyName("type")] public Type Type { get; set; }
|
||||
|
||||
[JsonPropertyName("gfx")] public int ItemID { get; set; }
|
||||
[JsonPropertyName("type")]
|
||||
public Type Type { get; set; }
|
||||
|
||||
#nullable enable
|
||||
[JsonPropertyName("hue")] public int? Hue { get; set; }
|
||||
[JsonPropertyName("gfx")]
|
||||
public int? ItemID { get; set; }
|
||||
|
||||
[JsonPropertyName("hue")]
|
||||
public int? Hue { get; set; }
|
||||
#nullable disable
|
||||
|
||||
public CAGCategory Parent { get; set; }
|
||||
|
|
|
|||
|
|
@ -1,433 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using Server.Items;
|
||||
using Server.Json;
|
||||
using Server.Utilities;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public static class Categorization
|
||||
{
|
||||
private static CategoryEntry m_RootItems, m_RootMobiles;
|
||||
|
||||
private static readonly Type typeofItem = typeof(Item);
|
||||
private static readonly Type typeofMobile = typeof(Mobile);
|
||||
private static readonly Type typeofConstructible = typeof(ConstructibleAttribute);
|
||||
|
||||
public static CategoryEntry Items
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RootItems == null)
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
return m_RootItems;
|
||||
}
|
||||
}
|
||||
|
||||
public static CategoryEntry Mobiles
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_RootMobiles == null)
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
return m_RootMobiles;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Initialize()
|
||||
{
|
||||
CommandSystem.Register("RebuildCategorization", AccessLevel.Administrator, RebuildCategorization_OnCommand);
|
||||
}
|
||||
|
||||
[Usage("RebuildCategorization"), Description("Rebuilds the categorization data file used by the Add command.")]
|
||||
public static void RebuildCategorization_OnCommand(CommandEventArgs e)
|
||||
{
|
||||
var root = new CategoryEntry(null, "Add Menu", new[] { Items, Mobiles });
|
||||
|
||||
var ceList = new List<CategoryEntry>();
|
||||
ceList.AddRange(root.SubCategories);
|
||||
|
||||
Export(ceList, "Data/objects.json");
|
||||
|
||||
e.Mobile.SendMessage("Categorization menu rebuilt.");
|
||||
}
|
||||
|
||||
public static void Export(List<CategoryEntry> ceList, string fileName)
|
||||
{
|
||||
var list = new List<CAGJson>();
|
||||
foreach (var ce in ceList)
|
||||
{
|
||||
RecurseExport(list, ce, null);
|
||||
}
|
||||
|
||||
JsonConfig.Serialize(fileName, list);
|
||||
}
|
||||
|
||||
#nullable enable
|
||||
public static void RecurseExport(List<CAGJson> list, CategoryEntry ce, string? category)
|
||||
{
|
||||
category = string.IsNullOrWhiteSpace(category) ? ce.Title : $"{category}{ce.Title}";
|
||||
|
||||
if (ce.Matched.Count > 0)
|
||||
{
|
||||
var objects = new CAGObject[ce.Matched.Count];
|
||||
|
||||
for (var i = 0; i < ce.Matched.Count; i++)
|
||||
{
|
||||
var cte = ce.Matched[i];
|
||||
if (cte.Object is Item item)
|
||||
{
|
||||
var itemID = item.ItemID;
|
||||
|
||||
if (item is BaseAddon addon && addon.Components.Count == 1)
|
||||
{
|
||||
itemID = addon.Components[0].ItemID;
|
||||
}
|
||||
|
||||
if (itemID > TileData.MaxItemValue)
|
||||
{
|
||||
itemID = 1;
|
||||
}
|
||||
|
||||
int? hue = item.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
|
||||
objects[i] = new CAGObject
|
||||
{
|
||||
Type = cte.Type,
|
||||
ItemID = itemID,
|
||||
Hue = hue == 0 ? null : hue
|
||||
};
|
||||
}
|
||||
|
||||
if (cte.Object is Mobile m)
|
||||
{
|
||||
var itemID = ShrinkTable.Lookup(m, 1);
|
||||
|
||||
int? hue = m.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
{
|
||||
hue = 0;
|
||||
}
|
||||
|
||||
objects[i] = new CAGObject
|
||||
{
|
||||
Type = cte.Type,
|
||||
ItemID = itemID,
|
||||
Hue = hue == 0 ? null : hue
|
||||
};
|
||||
}
|
||||
|
||||
throw new InvalidCastException(
|
||||
$"Categorization Type Entry: {cte.Type.Name} is not a valid type."
|
||||
);
|
||||
}
|
||||
|
||||
list.Add(
|
||||
new CAGJson
|
||||
{
|
||||
Category = category,
|
||||
Objects = objects
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
var subCats = new List<CategoryEntry>(ce.SubCategories);
|
||||
|
||||
subCats.Sort(new CategorySorter());
|
||||
|
||||
for (var i = 0; i < subCats.Count; i++)
|
||||
{
|
||||
var subCat = subCats[i];
|
||||
RecurseExport(list, subCat, category);
|
||||
}
|
||||
}
|
||||
#nullable disable
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
var types = new List<Type>();
|
||||
|
||||
AddTypes(Core.Assembly, types);
|
||||
|
||||
for (var i = 0; i < AssemblyHandler.Assemblies.Length; ++i)
|
||||
{
|
||||
AddTypes(AssemblyHandler.Assemblies[i], types);
|
||||
}
|
||||
|
||||
m_RootItems = Load(types, "Data/items.cfg");
|
||||
m_RootMobiles = Load(types, "Data/mobiles.cfg");
|
||||
}
|
||||
|
||||
private static CategoryEntry Load(List<Type> types, string config)
|
||||
{
|
||||
var lines = CategoryLine.Load(config);
|
||||
|
||||
if (lines.Length <= 0)
|
||||
{
|
||||
return new CategoryEntry();
|
||||
}
|
||||
|
||||
var index = 0;
|
||||
var root = new CategoryEntry(null, lines, ref index);
|
||||
|
||||
Fill(root, types);
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
private static bool IsConstructible(Type type)
|
||||
{
|
||||
if (!type.IsSubclassOf(typeofItem) && !type.IsSubclassOf(typeofMobile))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
var ctor = type.GetConstructor(Type.EmptyTypes);
|
||||
|
||||
return ctor?.IsDefined(typeofConstructible, false) == true;
|
||||
}
|
||||
|
||||
private static void AddTypes(Assembly asm, List<Type> types)
|
||||
{
|
||||
var allTypes = asm.GetTypes();
|
||||
|
||||
for (var i = 0; i < allTypes.Length; ++i)
|
||||
{
|
||||
var type = allTypes[i];
|
||||
|
||||
if (type.IsAbstract)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (IsConstructible(type))
|
||||
{
|
||||
types.Add(type);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void Fill(CategoryEntry root, List<Type> list)
|
||||
{
|
||||
for (var i = 0; i < list.Count; ++i)
|
||||
{
|
||||
var type = list[i];
|
||||
var match = GetDeepestMatch(root, type);
|
||||
|
||||
if (match == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
match.Matched.Add(new CategoryTypeEntry(type));
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static CategoryEntry GetDeepestMatch(CategoryEntry root, Type type)
|
||||
{
|
||||
if (!root.IsMatch(type))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
for (var i = 0; i < root.SubCategories.Length; ++i)
|
||||
{
|
||||
var check = GetDeepestMatch(root.SubCategories[i], type);
|
||||
|
||||
if (check != null)
|
||||
{
|
||||
return check;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
public class CategorySorter : IComparer<CategoryEntry>
|
||||
{
|
||||
public int Compare(CategoryEntry x, CategoryEntry y) =>
|
||||
string.CompareOrdinal(x?.Title, y?.Title);
|
||||
}
|
||||
|
||||
public class CategoryTypeSorter : IComparer<CategoryTypeEntry>
|
||||
{
|
||||
public int Compare(CategoryTypeEntry x, CategoryTypeEntry y) =>
|
||||
string.CompareOrdinal(x?.Type.Name, y?.Type.Name);
|
||||
}
|
||||
|
||||
public class CategoryTypeEntry
|
||||
{
|
||||
public CategoryTypeEntry(Type type)
|
||||
{
|
||||
Type = type;
|
||||
Object = type.CreateInstance<object>();
|
||||
}
|
||||
|
||||
public Type Type { get; }
|
||||
|
||||
public object Object { get; }
|
||||
}
|
||||
|
||||
public class CategoryEntry
|
||||
{
|
||||
public CategoryEntry(CategoryEntry parent = null, string title = "(empty)", CategoryEntry[] subCats = null)
|
||||
{
|
||||
Parent = parent;
|
||||
Title = title;
|
||||
SubCategories = subCats ?? Array.Empty<CategoryEntry>();
|
||||
Matches = Array.Empty<Type>();
|
||||
Matched = new List<CategoryTypeEntry>();
|
||||
}
|
||||
|
||||
public CategoryEntry(CategoryEntry parent, CategoryLine[] lines, ref int index)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
var text = lines[index].Text;
|
||||
|
||||
var start = text.IndexOfOrdinal('(');
|
||||
|
||||
if (start < 0)
|
||||
{
|
||||
throw new FormatException($"Input string not correctly formatted ('{text}')");
|
||||
}
|
||||
|
||||
Title = text.Substring(0, start).Trim();
|
||||
|
||||
var end = text.IndexOf(')', ++start);
|
||||
|
||||
if (end < start)
|
||||
{
|
||||
throw new FormatException($"Input string not correctly formatted ('{text}')");
|
||||
}
|
||||
|
||||
text = text.Substring(start, end - start);
|
||||
var split = text.Split(';');
|
||||
|
||||
var list = new List<Type>();
|
||||
|
||||
for (var i = 0; i < split.Length; ++i)
|
||||
{
|
||||
var type = AssemblyHandler.FindTypeByName(split[i].Trim());
|
||||
|
||||
if (type == null)
|
||||
{
|
||||
Console.WriteLine("Match type not found ('{0}')", split[i].Trim());
|
||||
}
|
||||
else
|
||||
{
|
||||
list.Add(type);
|
||||
}
|
||||
}
|
||||
|
||||
Matches = list.ToArray();
|
||||
list.Clear();
|
||||
|
||||
var ourIndentation = lines[index].Indentation;
|
||||
|
||||
++index;
|
||||
|
||||
var entryList = new List<CategoryEntry>();
|
||||
|
||||
while (index < lines.Length && lines[index].Indentation > ourIndentation)
|
||||
{
|
||||
entryList.Add(new CategoryEntry(this, lines, ref index));
|
||||
}
|
||||
|
||||
SubCategories = entryList.ToArray();
|
||||
entryList.Clear();
|
||||
|
||||
Matched = new List<CategoryTypeEntry>();
|
||||
}
|
||||
|
||||
public string Title { get; }
|
||||
|
||||
public Type[] Matches { get; }
|
||||
|
||||
public CategoryEntry Parent { get; }
|
||||
|
||||
public CategoryEntry[] SubCategories { get; }
|
||||
|
||||
public List<CategoryTypeEntry> Matched { get; }
|
||||
|
||||
public bool IsMatch(Type type)
|
||||
{
|
||||
var isMatch = false;
|
||||
|
||||
for (var i = 0; !isMatch && i < Matches.Length; ++i)
|
||||
{
|
||||
isMatch = type == Matches[i] || type.IsSubclassOf(Matches[i]);
|
||||
}
|
||||
|
||||
return isMatch;
|
||||
}
|
||||
}
|
||||
|
||||
public class CategoryLine
|
||||
{
|
||||
public CategoryLine(string input)
|
||||
{
|
||||
int index;
|
||||
|
||||
for (index = 0; index < input.Length; ++index)
|
||||
{
|
||||
if (char.IsLetter(input, index))
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index >= input.Length)
|
||||
{
|
||||
throw new FormatException($"Input string not correctly formatted ('{input}')");
|
||||
}
|
||||
|
||||
Indentation = index;
|
||||
Text = input.Substring(index);
|
||||
}
|
||||
|
||||
public int Indentation { get; }
|
||||
|
||||
public string Text { get; }
|
||||
|
||||
public static CategoryLine[] Load(string path)
|
||||
{
|
||||
var list = new List<CategoryLine>();
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
using var ip = new StreamReader(path);
|
||||
string line;
|
||||
|
||||
while ((line = ip.ReadLine()) != null)
|
||||
{
|
||||
list.Add(new CategoryLine(line));
|
||||
}
|
||||
}
|
||||
|
||||
return list.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -218,7 +218,11 @@ namespace Server.Gumps
|
|||
|
||||
if (node is CAGObject obj)
|
||||
{
|
||||
var itemID = obj.ItemID;
|
||||
var itemID = obj.ItemID ?? 0;
|
||||
if (itemID == 0)
|
||||
{
|
||||
Console.WriteLine("Type {0} does not have a valid item id or shrink table entry.", obj.Type);
|
||||
}
|
||||
|
||||
var bounds = ItemBounds.Table[itemID];
|
||||
|
||||
|
|
|
|||
|
|
@ -253,8 +253,6 @@ namespace Server.Gumps
|
|||
{
|
||||
AddHtml(10, 125, 400, 20, Color(Center("Generating"), LabelColor32));
|
||||
|
||||
AddButtonLabeled(220, 150, GetButtonID(3, 107), "Rebuild Categorization");
|
||||
|
||||
AddButtonLabeled(20, 175, GetButtonID(3, 101), "Teleporters");
|
||||
AddButtonLabeled(220, 175, GetButtonID(3, 102), "Moongates");
|
||||
|
||||
|
|
@ -2127,10 +2125,6 @@ namespace Server.Gumps
|
|||
InvokeCommand("Decorate");
|
||||
notice = "Decoration has been generated.";
|
||||
break;
|
||||
case 107:
|
||||
InvokeCommand("RebuildCategorization");
|
||||
notice = "Categorization menu has been regenerated. The server should be restarted.";
|
||||
break;
|
||||
|
||||
case 110:
|
||||
InvokeCommand("Freeze");
|
||||
|
|
|
|||
|
|
@ -1,6 +1,8 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
[Furniture, Flippable(0xF65, 0xF67, 0xF69)]
|
||||
[Furniture]
|
||||
[Flippable(0xF65, 0xF67, 0xF69)]
|
||||
[TypeAlias("Server.Items.Easle")]
|
||||
public class Easel : Item
|
||||
{
|
||||
[Constructible]
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
namespace Server.Items
|
||||
{
|
||||
[TypeAlias("Server.Items.TelekinisisScroll")]
|
||||
public class TelekinesisScroll : SpellScroll
|
||||
{
|
||||
[Constructible]
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@ namespace Server
|
|||
public static int Lookup(int body, int defaultValue)
|
||||
{
|
||||
m_Table ??= Load();
|
||||
var index = body < m_Table.Length ? m_Table[body] : -1;
|
||||
var index = body >= 0 && body < m_Table.Length ? m_Table[body] : -1;
|
||||
if (index < 0)
|
||||
{
|
||||
return defaultValue;
|
||||
|
|
@ -35,10 +35,12 @@ namespace Server
|
|||
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
Console.WriteLine("No table found!");
|
||||
return Array.Empty<int>();
|
||||
}
|
||||
|
||||
var table = new List<int>();
|
||||
var list = new List<(int, int)>();
|
||||
var length = 0;
|
||||
|
||||
using var ip = new StreamReader(path);
|
||||
string line;
|
||||
|
|
@ -61,10 +63,14 @@ namespace Server
|
|||
var body = Utility.ToInt32(split[0]);
|
||||
var item = Utility.ToInt32(split[1]);
|
||||
|
||||
if (body >= 0)
|
||||
if (body < 0)
|
||||
{
|
||||
table[body] = item;
|
||||
continue;
|
||||
}
|
||||
|
||||
list.Add((body, item));
|
||||
|
||||
length = Math.Max(body + 1, length);
|
||||
}
|
||||
}
|
||||
catch
|
||||
|
|
@ -73,7 +79,13 @@ namespace Server
|
|||
}
|
||||
}
|
||||
|
||||
return table.ToArray();
|
||||
var table = new int[length];
|
||||
foreach (var (body, item) in list)
|
||||
{
|
||||
table[body] = item;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2567,7 +2567,7 @@ namespace Server.Mobiles
|
|||
}
|
||||
}
|
||||
|
||||
public override void DoHarmful(Mobile target, bool indirect)
|
||||
public override void DoHarmful(Mobile target, bool indirect = false)
|
||||
{
|
||||
base.DoHarmful(target, indirect);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue