Updates Data to JSON (#159)
This commit is contained in:
parent
d2f7e08de4
commit
1246a135f7
61 changed files with 18005 additions and 9152 deletions
28
Projects/UOContent/Commands/Object Creation/CAGCategory.cs
Normal file
28
Projects/UOContent/Commands/Object Creation/CAGCategory.cs
Normal file
|
|
@ -0,0 +1,28 @@
|
|||
using Server.Gumps;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class CAGCategory : CAGNode
|
||||
{
|
||||
private static CAGCategory m_Root;
|
||||
|
||||
public CAGCategory(string title, CAGCategory parent = null)
|
||||
{
|
||||
Title = title;
|
||||
Parent = parent;
|
||||
}
|
||||
|
||||
public override string Title { get; }
|
||||
|
||||
public CAGNode[] Nodes { get; set; }
|
||||
|
||||
public CAGCategory Parent { get; }
|
||||
|
||||
public static CAGCategory Root => m_Root ??= CAGLoader.Load();
|
||||
|
||||
public override void OnClick(Mobile from, int page)
|
||||
{
|
||||
from.SendGump(new CategorizedAddGump(from, this));
|
||||
}
|
||||
}
|
||||
}
|
||||
68
Projects/UOContent/Commands/Object Creation/CAGLoader.cs
Normal file
68
Projects/UOContent/Commands/Object Creation/CAGLoader.cs
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.Json.Serialization;
|
||||
using Server.Json;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public static class CAGLoader
|
||||
{
|
||||
public static CAGCategory Load()
|
||||
{
|
||||
var root = new CAGCategory("Add Menu");
|
||||
var path = Path.Combine(Core.BaseDirectory, "Data/objects.json");
|
||||
|
||||
List<CAGJson> list = JsonConfig.Deserialize<List<CAGJson>>(path);
|
||||
|
||||
// Not an optimized solution
|
||||
foreach (var cag in list)
|
||||
{
|
||||
var parent = root;
|
||||
// Navigate through the dot notation categories until we find the last one
|
||||
var categories = cag.Category.Split(".");
|
||||
for (int i = 0; i < categories.Length; i++)
|
||||
{
|
||||
var category = categories[i];
|
||||
var oldParent = parent;
|
||||
|
||||
for (int j = 0; j < parent.Nodes.Length; j++)
|
||||
{
|
||||
var node = parent.Nodes[i];
|
||||
if (category == node.Title && node is CAGCategory cat)
|
||||
{
|
||||
parent = cat;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (parent == oldParent)
|
||||
parent = new CAGCategory(category, parent);
|
||||
}
|
||||
|
||||
// Set the objects associated with the child most node
|
||||
parent.Nodes = new CAGNode[cag.Objects.Length];
|
||||
for (int i = 0; i < cag.Objects.Length; i++)
|
||||
{
|
||||
var obj = cag.Objects[i];
|
||||
obj.Parent = parent;
|
||||
parent.Nodes[i] = obj;
|
||||
}
|
||||
}
|
||||
|
||||
return root;
|
||||
}
|
||||
}
|
||||
|
||||
public class CAGJson
|
||||
{
|
||||
public CAGJson()
|
||||
{
|
||||
}
|
||||
|
||||
[JsonPropertyName("category")]
|
||||
public string Category { get; set; }
|
||||
|
||||
[JsonPropertyName("objects")]
|
||||
public CAGObject[] Objects { get; set; }
|
||||
}
|
||||
}
|
||||
8
Projects/UOContent/Commands/Object Creation/CAGNode.cs
Normal file
8
Projects/UOContent/Commands/Object Creation/CAGNode.cs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
namespace Server.Commands
|
||||
{
|
||||
public abstract class CAGNode
|
||||
{
|
||||
public abstract string Title { get; }
|
||||
public abstract void OnClick(Mobile from, int page);
|
||||
}
|
||||
}
|
||||
40
Projects/UOContent/Commands/Object Creation/CAGObject.cs
Normal file
40
Projects/UOContent/Commands/Object Creation/CAGObject.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System;
|
||||
using System.Text.Json.Serialization;
|
||||
using Server.Gumps;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class CAGObject : CAGNode
|
||||
{
|
||||
public CAGObject()
|
||||
{
|
||||
}
|
||||
|
||||
[JsonPropertyName("type")]
|
||||
public Type Type { get; set; }
|
||||
|
||||
[JsonPropertyName("gfx")]
|
||||
public int ItemID { get; set; }
|
||||
|
||||
[JsonPropertyName("hue")]
|
||||
public int? Hue { get; set; }
|
||||
|
||||
public CAGCategory Parent { get; set; }
|
||||
|
||||
public override string Title => Type == null ? "bad type" : Type.Name;
|
||||
|
||||
public override void OnClick(Mobile from, int page)
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
from.SendMessage("That is an invalid type name.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandSystem.Handle(from, $"{CommandSystem.Prefix}Add {Type.Name}");
|
||||
|
||||
from.SendGump(new CategorizedAddGump(from, Parent, page));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,15 +1,15 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using Server.Items;
|
||||
using Server.Json;
|
||||
using Server.Utilities;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class Categorization
|
||||
public static class Categorization
|
||||
{
|
||||
private static CategoryEntry m_RootItems, m_RootMobiles;
|
||||
|
||||
|
|
@ -50,95 +50,87 @@ namespace Server.Commands
|
|||
{
|
||||
CategoryEntry root = new CategoryEntry(null, "Add Menu", new[] { Items, Mobiles });
|
||||
|
||||
Export(root, "Data/objects.xml", "Objects");
|
||||
List<CategoryEntry> ceList = new List<CategoryEntry>();
|
||||
ceList.AddRange(root.SubCategories);
|
||||
|
||||
Export(ceList, "Data/objects.json");
|
||||
|
||||
e.Mobile.SendMessage("Categorization menu rebuilt.");
|
||||
}
|
||||
|
||||
public static void Export(CategoryEntry ce, string fileName, string title)
|
||||
public static void Export(List<CategoryEntry> ceList, string fileName)
|
||||
{
|
||||
XmlTextWriter xml = new XmlTextWriter(fileName, Encoding.UTF8);
|
||||
List<CAGJson> list = new List<CAGJson>();
|
||||
foreach (var ce in ceList)
|
||||
RecurseExport(list, ce, null);
|
||||
|
||||
xml.Indentation = 1;
|
||||
xml.IndentChar = '\t';
|
||||
xml.Formatting = Formatting.Indented;
|
||||
|
||||
xml.WriteStartDocument(true);
|
||||
|
||||
RecurseExport(xml, ce);
|
||||
|
||||
xml.Flush();
|
||||
xml.Close();
|
||||
JsonConfig.Serialize(fileName, list);
|
||||
}
|
||||
|
||||
public static void RecurseExport(XmlTextWriter xml, CategoryEntry ce)
|
||||
public static void RecurseExport(List<CAGJson> list, CategoryEntry ce, string category)
|
||||
{
|
||||
xml.WriteStartElement("category");
|
||||
category = string.IsNullOrWhiteSpace(category) ? ce.Title : $"{category}{ce.Title}";
|
||||
|
||||
xml.WriteAttributeString("title", ce.Title);
|
||||
if (ce.Matched.Count > 0)
|
||||
list.Add(new CAGJson
|
||||
{
|
||||
Category = category,
|
||||
Objects = ce.Matched.Select(cte =>
|
||||
{
|
||||
if (cte.Object is Item item)
|
||||
{
|
||||
int 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;
|
||||
|
||||
return new CAGObject
|
||||
{
|
||||
Type = cte.Type,
|
||||
ItemID = itemID,
|
||||
Hue = hue == 0 ? null : hue
|
||||
};
|
||||
}
|
||||
|
||||
if (cte.Object is Mobile m)
|
||||
{
|
||||
int itemID = ShrinkTable.Lookup(m, 1);
|
||||
|
||||
int? hue = m.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
hue = 0;
|
||||
|
||||
return 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.");
|
||||
}).ToArray()
|
||||
});
|
||||
|
||||
List<CategoryEntry> subCats = new List<CategoryEntry>(ce.SubCategories);
|
||||
|
||||
subCats.Sort(new CategorySorter());
|
||||
|
||||
for (int i = 0; i < subCats.Count; ++i)
|
||||
RecurseExport(xml, subCats[i]);
|
||||
|
||||
ce.Matched.Sort(new CategoryTypeSorter());
|
||||
|
||||
for (int i = 0; i < ce.Matched.Count; ++i)
|
||||
for (int i = 0; i < subCats.Count; i++)
|
||||
{
|
||||
CategoryTypeEntry cte = ce.Matched[i];
|
||||
|
||||
xml.WriteStartElement("object");
|
||||
|
||||
xml.WriteAttributeString("type", cte.Type.ToString());
|
||||
|
||||
if (cte.Object is Item item)
|
||||
{
|
||||
int itemID = item.ItemID;
|
||||
|
||||
if (item is BaseAddon addon && addon.Components.Count == 1)
|
||||
itemID = addon.Components[0].ItemID;
|
||||
|
||||
if (itemID > TileData.MaxItemValue)
|
||||
itemID = 1;
|
||||
|
||||
xml.WriteAttributeString("gfx", XmlConvert.ToString(itemID));
|
||||
|
||||
int hue = item.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
hue = 0;
|
||||
|
||||
if (hue != 0)
|
||||
xml.WriteAttributeString("hue", XmlConvert.ToString(hue));
|
||||
|
||||
item.Delete();
|
||||
}
|
||||
else if (cte.Object is Mobile mob)
|
||||
{
|
||||
int itemID = ShrinkTable.Lookup(mob, 1);
|
||||
|
||||
xml.WriteAttributeString("gfx", XmlConvert.ToString(itemID));
|
||||
|
||||
int hue = mob.Hue & 0x7FFF;
|
||||
|
||||
if ((hue & 0x4000) != 0)
|
||||
hue = 0;
|
||||
|
||||
if (hue != 0)
|
||||
xml.WriteAttributeString("hue", XmlConvert.ToString(hue));
|
||||
|
||||
mob.Delete();
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
var subCat = subCats[i];
|
||||
RecurseExport(list, subCat, category);
|
||||
}
|
||||
|
||||
xml.WriteEndElement();
|
||||
}
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
List<Type> types = new List<Type>();
|
||||
|
|
@ -156,17 +148,15 @@ namespace Server.Commands
|
|||
{
|
||||
CategoryLine[] lines = CategoryLine.Load(config);
|
||||
|
||||
if (lines.Length > 0)
|
||||
{
|
||||
int index = 0;
|
||||
CategoryEntry root = new CategoryEntry(null, lines, ref index);
|
||||
if (lines.Length <= 0) return new CategoryEntry();
|
||||
|
||||
Fill(root, types);
|
||||
int index = 0;
|
||||
CategoryEntry root = new CategoryEntry(null, lines, ref index);
|
||||
|
||||
return root;
|
||||
}
|
||||
Fill(root, types);
|
||||
|
||||
return root;
|
||||
|
||||
return new CategoryEntry();
|
||||
}
|
||||
|
||||
private static bool IsConstructible(Type type)
|
||||
|
|
@ -240,13 +230,12 @@ namespace Server.Commands
|
|||
string a = x?.Title;
|
||||
string b = y?.Title;
|
||||
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
|
||||
if (a == null)
|
||||
return 1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
return a switch
|
||||
{
|
||||
null when b == null => 0,
|
||||
null => 1,
|
||||
_ => a.CompareTo(b)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -257,13 +246,12 @@ namespace Server.Commands
|
|||
string a = x?.Type.Name;
|
||||
string b = y?.Type.Name;
|
||||
|
||||
if (a == null && b == null)
|
||||
return 0;
|
||||
|
||||
if (a == null)
|
||||
return 1;
|
||||
|
||||
return a.CompareTo(b);
|
||||
return a switch
|
||||
{
|
||||
null when b == null => 0,
|
||||
null => 1,
|
||||
_ => a.CompareTo(b)
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1,143 +1,9 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Server.Commands;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public abstract class CAGNode
|
||||
{
|
||||
public abstract string Caption { get; }
|
||||
public abstract void OnClick(Mobile from, int page);
|
||||
}
|
||||
|
||||
public class CAGObject : CAGNode
|
||||
{
|
||||
public CAGObject(CAGCategory parent, XmlTextReader xml)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
if (xml.MoveToAttribute("type"))
|
||||
Type = AssemblyHandler.FindFirstTypeForName(xml.Value, false);
|
||||
|
||||
if (xml.MoveToAttribute("gfx"))
|
||||
ItemID = XmlConvert.ToInt32(xml.Value);
|
||||
|
||||
if (xml.MoveToAttribute("hue"))
|
||||
Hue = XmlConvert.ToInt32(xml.Value);
|
||||
}
|
||||
|
||||
public Type Type { get; }
|
||||
|
||||
public int ItemID { get; }
|
||||
|
||||
public int Hue { get; }
|
||||
|
||||
public CAGCategory Parent { get; }
|
||||
|
||||
public override string Caption => Type == null ? "bad type" : Type.Name;
|
||||
|
||||
public override void OnClick(Mobile from, int page)
|
||||
{
|
||||
if (Type == null)
|
||||
{
|
||||
from.SendMessage("That is an invalid type name.");
|
||||
}
|
||||
else
|
||||
{
|
||||
CommandSystem.Handle(from, $"{CommandSystem.Prefix}Add {Type.Name}");
|
||||
|
||||
from.SendGump(new CategorizedAddGump(from, Parent, page));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class CAGCategory : CAGNode
|
||||
{
|
||||
private static CAGCategory m_Root;
|
||||
|
||||
private CAGCategory()
|
||||
{
|
||||
Title = "no data";
|
||||
Nodes = Array.Empty<CAGNode>();
|
||||
}
|
||||
|
||||
public CAGCategory(CAGCategory parent, XmlTextReader xml)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
if (xml.MoveToAttribute("title"))
|
||||
Title = xml.Value;
|
||||
else
|
||||
Title = "empty";
|
||||
|
||||
if (Title == "Docked")
|
||||
Title = "Docked 2";
|
||||
|
||||
if (xml.IsEmptyElement)
|
||||
{
|
||||
Nodes = Array.Empty<CAGNode>();
|
||||
}
|
||||
else
|
||||
{
|
||||
List<CAGNode> nodes = new List<CAGNode>();
|
||||
|
||||
while (xml.Read() && xml.NodeType != XmlNodeType.EndElement)
|
||||
if (xml.NodeType == XmlNodeType.Element && xml.Name == "object")
|
||||
{
|
||||
nodes.Add(new CAGObject(this, xml));
|
||||
}
|
||||
else if (xml.NodeType == XmlNodeType.Element && xml.Name == "category")
|
||||
{
|
||||
if (!xml.IsEmptyElement)
|
||||
nodes.Add(new CAGCategory(this, xml));
|
||||
}
|
||||
else
|
||||
{
|
||||
xml.Skip();
|
||||
}
|
||||
|
||||
Nodes = nodes.ToArray();
|
||||
}
|
||||
}
|
||||
|
||||
public string Title { get; }
|
||||
|
||||
public CAGNode[] Nodes { get; }
|
||||
|
||||
public CAGCategory Parent { get; }
|
||||
|
||||
public override string Caption => Title;
|
||||
|
||||
public static CAGCategory Root => m_Root ?? (m_Root = Load("Data/objects.xml"));
|
||||
|
||||
public override void OnClick(Mobile from, int page)
|
||||
{
|
||||
from.SendGump(new CategorizedAddGump(from, this));
|
||||
}
|
||||
|
||||
public static CAGCategory Load(string path)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
XmlTextReader xml = new XmlTextReader(path) { WhitespaceHandling = WhitespaceHandling.None };
|
||||
|
||||
while (xml.Read())
|
||||
if (xml.Name == "category" && xml.NodeType == XmlNodeType.Element)
|
||||
{
|
||||
CAGCategory cat = new CAGCategory(null, xml);
|
||||
|
||||
xml.Close();
|
||||
|
||||
return cat;
|
||||
}
|
||||
}
|
||||
|
||||
return new CAGCategory();
|
||||
}
|
||||
}
|
||||
|
||||
public class CategorizedAddGump : Gump
|
||||
{
|
||||
public static bool OldStyle = PropsConfig.OldStyle;
|
||||
|
|
@ -266,7 +132,7 @@ namespace Server.Gumps
|
|||
EntryGumpID);
|
||||
|
||||
AddHtml(x + TextOffsetX, y + (EntryHeight - 20) / 2, emptyWidth - TextOffsetX, EntryHeight,
|
||||
$"<center>{m_Category.Caption}</center>");
|
||||
$"<center>{m_Category.Title}</center>");
|
||||
|
||||
x += emptyWidth + OffsetSize;
|
||||
|
||||
|
|
@ -305,7 +171,7 @@ namespace Server.Gumps
|
|||
|
||||
AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID);
|
||||
AddLabelCropped(x + TextOffsetX, y + (EntryHeight - 20) / 2, EntryWidth - TextOffsetX, EntryHeight, TextHue,
|
||||
node.Caption);
|
||||
node.Title);
|
||||
|
||||
x += EntryWidth + OffsetSize;
|
||||
|
||||
|
|
@ -11,7 +11,7 @@ using Server.Utilities;
|
|||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public class DecorateMag
|
||||
public static class DecorateMag
|
||||
{
|
||||
private static Mobile m_Mobile;
|
||||
private static int m_Count;
|
||||
|
|
@ -5,30 +5,28 @@ using System.Linq;
|
|||
using System.Text.Json;
|
||||
using System.Text.Json.Serialization;
|
||||
using Server.Items;
|
||||
using Server.Json;
|
||||
|
||||
namespace Server.Commands
|
||||
{
|
||||
public struct Location
|
||||
{
|
||||
[JsonPropertyName("point"), JsonConverter(typeof(Point3DConverter))]
|
||||
public Point3D Pos { get; set; }
|
||||
[JsonPropertyName("map"), JsonConverter(typeof(MapConverter))]
|
||||
public Map Map { get; set; }
|
||||
public override string ToString() => $"({Map.Name}:{Pos.X},{Pos.Y},{Pos.Z})";
|
||||
public override int GetHashCode() => ToString().GetHashCode();
|
||||
}
|
||||
|
||||
public struct TeleporterDefinition
|
||||
{
|
||||
[JsonPropertyName("source")]
|
||||
public Location Source { get; set; }
|
||||
[JsonPropertyName("destination")]
|
||||
public Location Destination { get; set; }
|
||||
[JsonPropertyName("src")]
|
||||
public WorldLocation Source { get; set; }
|
||||
|
||||
[JsonPropertyName("dst")]
|
||||
public WorldLocation Destination { get; set; }
|
||||
|
||||
[JsonPropertyName("back")]
|
||||
public bool Back { get; set; }
|
||||
|
||||
public override string ToString() => $"{{{Source},{Destination},{Back}}}";
|
||||
public override int GetHashCode() => ToString().GetHashCode();
|
||||
|
||||
public bool Equals(TeleporterDefinition other) =>
|
||||
Source.Equals(other.Source) && Destination.Equals(other.Destination) && Back == other.Back;
|
||||
|
||||
public override bool Equals(object obj) => obj is TeleporterDefinition other && Equals(other);
|
||||
|
||||
public override int GetHashCode() => HashCode.Combine(Source, Destination, Back);
|
||||
}
|
||||
|
||||
public static class GenTeleporter
|
||||
|
|
@ -124,11 +122,11 @@ namespace Server.Commands
|
|||
|
||||
private static bool IsWithinZ(int delta) => delta >= -12 && delta <= 12;
|
||||
|
||||
public static int DeleteTeleporters(Location location)
|
||||
public static int DeleteTeleporters(WorldLocation worldLocation)
|
||||
{
|
||||
IPooledEnumerable<Teleporter> eable = location.Map.GetItemsInRange<Teleporter>(location.Pos, 0);
|
||||
IPooledEnumerable<Teleporter> eable = worldLocation.Map.GetItemsInRange<Teleporter>(worldLocation, 0);
|
||||
var items = eable
|
||||
.Where(x => !(x is KeywordTeleporter || x is SkillTeleporter) && IsWithinZ(x.Z - location.Pos.Z));
|
||||
.Where(x => !(x is KeywordTeleporter || x is SkillTeleporter) && IsWithinZ(x.Z - worldLocation.Z));
|
||||
int count = 0;
|
||||
foreach (var item in items)
|
||||
{
|
||||
|
|
@ -143,11 +141,11 @@ namespace Server.Commands
|
|||
{
|
||||
DelCount += DeleteTeleporters(telDef.Source);
|
||||
Count++;
|
||||
new Teleporter(telDef.Destination.Pos, telDef.Destination.Map).MoveToWorld(telDef.Source.Pos, telDef.Source.Map);
|
||||
new Teleporter(telDef.Destination, telDef.Destination.Map).MoveToWorld(telDef.Source, telDef.Source.Map);
|
||||
if (!telDef.Back) return;
|
||||
DelCount += DeleteTeleporters(telDef.Destination);
|
||||
Count++;
|
||||
new Teleporter(telDef.Source.Pos, telDef.Source.Map).MoveToWorld(telDef.Destination.Pos, telDef.Destination.Map);
|
||||
new Teleporter(telDef.Source, telDef.Source.Map).MoveToWorld(telDef.Destination, telDef.Destination.Map);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -36,11 +36,7 @@ namespace Server.Engines.Spawners
|
|||
return;
|
||||
}
|
||||
|
||||
JsonSerializerOptions options = new JsonSerializerOptions();
|
||||
options.Converters.Add(new MapConverterFactory());
|
||||
options.Converters.Add(new Point3DConverterFactory());
|
||||
options.Converters.Add(new TimeSpanConverterFactory());
|
||||
options.Converters.Add(new TextDefinitionConverterFactory());
|
||||
JsonSerializerOptions options = JsonConfig.GetOptions(new TextDefinitionConverterFactory());
|
||||
|
||||
for (int i = 0; i < files.Length; i++)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -1,38 +0,0 @@
|
|||
using System.Xml;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class ChildNode : IGoNode
|
||||
{
|
||||
public ChildNode(XmlTextReader xml, ParentNode parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Parse(xml);
|
||||
}
|
||||
|
||||
public ParentNode Parent { get; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
public Point3D Location { get; private set; }
|
||||
|
||||
private void Parse(XmlTextReader xml)
|
||||
{
|
||||
Name = xml.MoveToAttribute("name") ? xml.Value : "empty";
|
||||
|
||||
int x = 0, y = 0, z = 0;
|
||||
|
||||
if (xml.MoveToAttribute("x"))
|
||||
x = Utility.ToInt32(xml.Value);
|
||||
|
||||
if (xml.MoveToAttribute("y"))
|
||||
y = Utility.ToInt32(xml.Value);
|
||||
|
||||
if (xml.MoveToAttribute("z"))
|
||||
z = Utility.ToInt32(xml.Value);
|
||||
|
||||
Location = new Point3D(x, y, z);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Projects/UOContent/Gumps/Go/GoCategory.cs
Normal file
18
Projects/UOContent/Gumps/Go/GoCategory.cs
Normal file
|
|
@ -0,0 +1,18 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GoCategory
|
||||
{
|
||||
public GoCategory Parent { get; set; }
|
||||
|
||||
[JsonPropertyName("locations")]
|
||||
public GoLocation[] Locations { get; set; }
|
||||
|
||||
[JsonPropertyName("categories")]
|
||||
public GoCategory[] Categories { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -4,11 +4,12 @@ namespace Server.Gumps
|
|||
{
|
||||
public class GoGump : Gump
|
||||
{
|
||||
public static readonly LocationTree Felucca = new LocationTree("felucca.xml", Map.Felucca);
|
||||
public static readonly LocationTree Trammel = new LocationTree("trammel.xml", Map.Trammel);
|
||||
public static readonly LocationTree Ilshenar = new LocationTree("ilshenar.xml", Map.Ilshenar);
|
||||
public static readonly LocationTree Malas = new LocationTree("malas.xml", Map.Malas);
|
||||
public static readonly LocationTree Tokuno = new LocationTree("tokuno.xml", Map.Tokuno);
|
||||
private static LocationTree Felucca;
|
||||
private static LocationTree Trammel;
|
||||
private static LocationTree Ilshenar;
|
||||
private static LocationTree Malas;
|
||||
private static LocationTree Tokuno;
|
||||
private static LocationTree TerMur;
|
||||
|
||||
public static bool OldStyle = PropsConfig.OldStyle;
|
||||
|
||||
|
|
@ -61,16 +62,43 @@ namespace Server.Gumps
|
|||
|
||||
private static readonly int BackWidth = BorderSize + TotalWidth + BorderSize;
|
||||
private static readonly int BackHeight = BorderSize + TotalHeight + BorderSize;
|
||||
private readonly ParentNode m_Node;
|
||||
private readonly GoCategory m_Node;
|
||||
private readonly int m_Page;
|
||||
|
||||
private readonly LocationTree m_Tree;
|
||||
|
||||
private GoGump(int page, Mobile from, LocationTree tree, ParentNode node) : base(50, 50)
|
||||
public static void DisplayTo(Mobile from)
|
||||
{
|
||||
LocationTree tree;
|
||||
|
||||
if (from.Map == Map.Ilshenar)
|
||||
tree = Ilshenar ??= new LocationTree("ilshenar", Map.Ilshenar);
|
||||
else if (from.Map == Map.Felucca)
|
||||
tree = Felucca ??= new LocationTree("felucca", Map.Felucca);
|
||||
else if (from.Map == Map.Trammel)
|
||||
tree = Trammel ??= new LocationTree("trammel", Map.Trammel);
|
||||
else if (from.Map == Map.Malas)
|
||||
tree = Malas ??= new LocationTree("malas", Map.Malas);
|
||||
else if (from.Map == Map.Tokuno)
|
||||
tree = Tokuno ??= new LocationTree("tokuno", Map.Tokuno);
|
||||
else
|
||||
tree = TerMur ??= new LocationTree("termur", Map.TerMur);
|
||||
|
||||
if (!tree.LastBranch.TryGetValue(from, out GoCategory branch))
|
||||
branch = tree.Root;
|
||||
|
||||
if (branch != null)
|
||||
from.SendGump(new GoGump(0, from, tree, branch));
|
||||
}
|
||||
|
||||
private GoGump(int page, Mobile from, LocationTree tree, GoCategory node) : base(50, 50)
|
||||
{
|
||||
from.CloseGump<GoGump>();
|
||||
|
||||
tree.LastBranch[from] = node;
|
||||
if (node == tree.Root)
|
||||
tree.LastBranch.Remove(from);
|
||||
else
|
||||
tree.LastBranch[from] = node;
|
||||
|
||||
m_Page = page;
|
||||
m_Tree = tree;
|
||||
|
|
@ -79,7 +107,7 @@ namespace Server.Gumps
|
|||
int x = BorderSize + OffsetSize;
|
||||
int y = BorderSize + OffsetSize;
|
||||
|
||||
int count = node.Children.Length - page * EntryCount;
|
||||
int count = node.Categories.Length + node.Locations.Length - page * EntryCount;
|
||||
|
||||
if (count < 0)
|
||||
count = 0;
|
||||
|
|
@ -138,7 +166,7 @@ namespace Server.Gumps
|
|||
if (!OldStyle)
|
||||
AddImageTiled(x, y, NextWidth, EntryHeight, HeaderGumpID);
|
||||
|
||||
if ((page + 1) * EntryCount < node.Children.Length)
|
||||
if ((page + 1) * EntryCount < node.Categories.Length + node.Locations.Length)
|
||||
{
|
||||
AddButton(x + NextOffsetX, y + NextOffsetY, NextButtonID1, NextButtonID2, 3, GumpButtonType.Reply, 1);
|
||||
|
||||
|
|
@ -146,13 +174,14 @@ namespace Server.Gumps
|
|||
AddLabel(x + NextLabelOffsetX, y + NextLabelOffsetY, TextHue, "Next");
|
||||
}
|
||||
|
||||
for (int i = 0, index = page * EntryCount; i < EntryCount && index < node.Children.Length; ++i, ++index)
|
||||
int totalEntryCount = node.Categories.Length + node.Locations.Length;
|
||||
|
||||
for (int i = 0, index = page * EntryCount; i < EntryCount && index < totalEntryCount; ++i, ++index)
|
||||
{
|
||||
x = BorderSize + OffsetSize;
|
||||
y += EntryHeight + OffsetSize;
|
||||
|
||||
IGoNode child = node.Children[index];
|
||||
string name = child.Name;
|
||||
string name = index >= node.Categories.Length ? node.Locations[index].Name : node.Categories[index].Name;
|
||||
|
||||
AddImageTiled(x, y, EntryWidth, EntryHeight, EntryGumpID);
|
||||
AddLabelCropped(x + TextOffsetX, y, EntryWidth - TextOffsetX, EntryHeight, TextHue, name);
|
||||
|
|
@ -166,28 +195,6 @@ namespace Server.Gumps
|
|||
}
|
||||
}
|
||||
|
||||
public static void DisplayTo(Mobile from)
|
||||
{
|
||||
LocationTree tree;
|
||||
|
||||
if (from.Map == Map.Ilshenar)
|
||||
tree = Ilshenar;
|
||||
else if (from.Map == Map.Felucca)
|
||||
tree = Felucca;
|
||||
else if (from.Map == Map.Trammel)
|
||||
tree = Trammel;
|
||||
else if (from.Map == Map.Malas)
|
||||
tree = Malas;
|
||||
else
|
||||
tree = Tokuno;
|
||||
|
||||
if (!tree.LastBranch.TryGetValue(from, out ParentNode branch))
|
||||
branch = tree.Root;
|
||||
|
||||
if (branch != null)
|
||||
from.SendGump(new GoGump(0, from, tree, branch));
|
||||
}
|
||||
|
||||
public override void OnResponse(NetState state, RelayInfo info)
|
||||
{
|
||||
Mobile from = state.Mobile;
|
||||
|
|
@ -210,7 +217,7 @@ namespace Server.Gumps
|
|||
}
|
||||
case 3:
|
||||
{
|
||||
if ((m_Page + 1) * EntryCount < m_Node.Children.Length)
|
||||
if ((m_Page + 1) * EntryCount < m_Node.Categories.Length + m_Node.Locations.Length)
|
||||
from.SendGump(new GoGump(m_Page + 1, from, m_Tree, m_Node));
|
||||
|
||||
break;
|
||||
|
|
@ -219,14 +226,18 @@ namespace Server.Gumps
|
|||
{
|
||||
int index = info.ButtonID - 4;
|
||||
|
||||
if (index >= 0 && index < m_Node.Children.Length)
|
||||
{
|
||||
IGoNode o = m_Node.Children[index];
|
||||
if (index < 0)
|
||||
break;
|
||||
|
||||
if (o is ParentNode node)
|
||||
from.SendGump(new GoGump(0, from, m_Tree, node));
|
||||
else
|
||||
from.MoveToWorld(((ChildNode)o).Location, m_Tree.Map);
|
||||
if (index < m_Node.Categories.Length)
|
||||
{
|
||||
from.SendGump(new GoGump(0, from, m_Tree, m_Node.Categories[index]));
|
||||
}
|
||||
else
|
||||
{
|
||||
index -= m_Node.Categories.Length;
|
||||
if (index < m_Node.Locations.Length)
|
||||
from.MoveToWorld(m_Node.Locations[index].Location, m_Tree.Map);
|
||||
}
|
||||
|
||||
break;
|
||||
|
|
|
|||
15
Projects/UOContent/Gumps/Go/GoLocation.cs
Normal file
15
Projects/UOContent/Gumps/Go/GoLocation.cs
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
using System.Text.Json.Serialization;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public class GoLocation
|
||||
{
|
||||
public GoCategory Parent { get; set; }
|
||||
|
||||
[JsonPropertyName("name")]
|
||||
public string Name { get; set; }
|
||||
|
||||
[JsonPropertyName("location")]
|
||||
public Point3D Location { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using Server.Json;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
|
|
@ -8,34 +9,50 @@ namespace Server.Gumps
|
|||
{
|
||||
public LocationTree(string fileName, Map map)
|
||||
{
|
||||
LastBranch = new Dictionary<Mobile, ParentNode>();
|
||||
LastBranch = new Dictionary<Mobile, GoCategory>();
|
||||
Map = map;
|
||||
|
||||
string path = Path.Combine("Data/Locations/", fileName);
|
||||
string path = Path.Combine($"Data/Locations/{fileName}.json");
|
||||
|
||||
if (File.Exists(path))
|
||||
if (!File.Exists(path))
|
||||
{
|
||||
XmlTextReader xml = new XmlTextReader(new StreamReader(path)) { WhitespaceHandling = WhitespaceHandling.None };
|
||||
Console.WriteLine("Go Locations: {0} does not exist", path);
|
||||
return;
|
||||
}
|
||||
|
||||
Root = Parse(xml);
|
||||
|
||||
xml.Close();
|
||||
try
|
||||
{
|
||||
Root = JsonConfig.Deserialize<GoCategory>(path);
|
||||
SetParents(Root);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Go Locations: Error in deserializing {0}", path);
|
||||
Console.WriteLine(e);
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<Mobile, ParentNode> LastBranch { get; }
|
||||
public Dictionary<Mobile, GoCategory> LastBranch { get; }
|
||||
|
||||
public Map Map { get; }
|
||||
|
||||
public ParentNode Root { get; }
|
||||
public GoCategory Root { get; }
|
||||
|
||||
private ParentNode Parse(XmlTextReader xml)
|
||||
private static void SetParents(GoCategory parent)
|
||||
{
|
||||
xml.Read();
|
||||
xml.Read();
|
||||
xml.Read();
|
||||
// Deserialization may leave these null
|
||||
parent.Categories ??= Array.Empty<GoCategory>();
|
||||
parent.Locations ??= Array.Empty<GoLocation>();
|
||||
|
||||
return new ParentNode(xml, null);
|
||||
for (int i = 0; i < parent.Categories.Length; i++)
|
||||
{
|
||||
GoCategory category = parent.Categories[i];
|
||||
category.Parent = parent;
|
||||
SetParents(category);
|
||||
}
|
||||
|
||||
for (int j = 0; j < parent.Locations.Length; j++)
|
||||
parent.Locations[j].Parent = parent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,53 +0,0 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml;
|
||||
|
||||
namespace Server.Gumps
|
||||
{
|
||||
public interface IGoNode
|
||||
{
|
||||
ParentNode Parent { get; }
|
||||
string Name { get; }
|
||||
}
|
||||
|
||||
public class ParentNode : IGoNode
|
||||
{
|
||||
public ParentNode(XmlTextReader xml, ParentNode parent)
|
||||
{
|
||||
Parent = parent;
|
||||
|
||||
Parse(xml);
|
||||
}
|
||||
|
||||
public ParentNode Parent { get; }
|
||||
|
||||
public IGoNode[] Children { get; private set; }
|
||||
|
||||
public string Name { get; private set; }
|
||||
|
||||
private void Parse(XmlTextReader xml)
|
||||
{
|
||||
Name = xml.MoveToAttribute("name") ? xml.Value : "empty";
|
||||
|
||||
if (xml.IsEmptyElement)
|
||||
Children = Array.Empty<IGoNode>();
|
||||
else
|
||||
{
|
||||
List<IGoNode> children = new List<IGoNode>();
|
||||
|
||||
while (xml.Read() && (xml.NodeType == XmlNodeType.Element || xml.NodeType == XmlNodeType.Comment))
|
||||
{
|
||||
if (xml.NodeType == XmlNodeType.Comment)
|
||||
continue;
|
||||
|
||||
if (xml.Name == "child")
|
||||
children.Add(new ChildNode(xml, this));
|
||||
else
|
||||
children.Add(new ParentNode(xml, this));
|
||||
}
|
||||
|
||||
Children = children.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using Server.Engines.VeteranRewards;
|
||||
using Server.Gumps;
|
||||
using Server.Multis;
|
||||
|
|
|
|||
|
|
@ -1,15 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Xml;
|
||||
using System.Text.Json.Serialization;
|
||||
using Server.Json;
|
||||
|
||||
namespace Server
|
||||
{
|
||||
public class NameList
|
||||
{
|
||||
public string Type { get; }
|
||||
[JsonPropertyName("type")]
|
||||
public string Type { get; set; }
|
||||
|
||||
public string[] List { get; }
|
||||
[JsonPropertyName("names")]
|
||||
public string[] List { get; set; }
|
||||
|
||||
public bool ContainsName(string name)
|
||||
{
|
||||
|
|
@ -20,22 +23,7 @@ namespace Server
|
|||
return false;
|
||||
}
|
||||
|
||||
public NameList(string type, XmlElement xml)
|
||||
{
|
||||
Type = type;
|
||||
List = xml.InnerText.Split(',');
|
||||
|
||||
for (int i = 0; i < List.Length; ++i)
|
||||
List[i] = Utility.Intern(List[i].Trim());
|
||||
}
|
||||
|
||||
public string GetRandomName()
|
||||
{
|
||||
if (List.Length > 0)
|
||||
return List[Utility.Random(List.Length)];
|
||||
|
||||
return "";
|
||||
}
|
||||
public string GetRandomName() => List.Length > 0 ? List[Utility.Random(List.Length)] : "";
|
||||
|
||||
public static NameList GetNameList(string type)
|
||||
{
|
||||
|
|
@ -45,53 +33,25 @@ namespace Server
|
|||
|
||||
public static string RandomName(string type) => GetNameList(type)?.GetRandomName() ?? "";
|
||||
|
||||
private static readonly Dictionary<string, NameList> m_Table;
|
||||
private static readonly Dictionary<string, NameList> m_Table = new Dictionary<string, NameList>(StringComparer.OrdinalIgnoreCase);
|
||||
|
||||
static NameList()
|
||||
public static void Configure()
|
||||
{
|
||||
m_Table = new Dictionary<string, NameList>(StringComparer.OrdinalIgnoreCase);
|
||||
// TODO: Turn this into a command so it can be updated in-game
|
||||
string filePath = Path.Combine(Core.BaseDirectory, "Data/names.json");
|
||||
|
||||
string filePath = Path.Combine(Core.BaseDirectory, "Data/names.xml");
|
||||
|
||||
if (!File.Exists(filePath))
|
||||
return;
|
||||
|
||||
try
|
||||
List<NameList> nameLists = JsonConfig.Deserialize<List<NameList>>(filePath);
|
||||
foreach (var nameList in nameLists)
|
||||
{
|
||||
Load(filePath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Console.WriteLine("Warning: Exception caught loading name lists:");
|
||||
Console.WriteLine(e);
|
||||
nameList.FixNames();
|
||||
m_Table.Add(nameList.Type, nameList);
|
||||
}
|
||||
}
|
||||
|
||||
private static void Load(string filePath)
|
||||
private void FixNames()
|
||||
{
|
||||
XmlDocument doc = new XmlDocument();
|
||||
doc.Load(filePath);
|
||||
|
||||
XmlElement root = doc["names"];
|
||||
|
||||
foreach (XmlElement element in root.GetElementsByTagName("namelist"))
|
||||
{
|
||||
string type = element.GetAttribute("type");
|
||||
|
||||
if (string.IsNullOrEmpty(type))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
NameList list = new NameList(type, element);
|
||||
|
||||
m_Table[type] = list;
|
||||
}
|
||||
catch
|
||||
{
|
||||
// ignored
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < List.Length; i++)
|
||||
List[i] = Utility.Intern(List[i].Trim());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,7 +4,6 @@ using System.Linq;
|
|||
using System.Net;
|
||||
using System.Net.NetworkInformation;
|
||||
using System.Net.Sockets;
|
||||
using Microsoft.AspNetCore.Connections;
|
||||
using Server.Network;
|
||||
|
||||
namespace Server.Misc
|
||||
|
|
@ -70,16 +69,15 @@ namespace Server.Misc
|
|||
try
|
||||
{
|
||||
NetState ns = e.State;
|
||||
ConnectionContext s = ns.Connection;
|
||||
|
||||
IPEndPoint ipep = (IPEndPoint)s.LocalEndPoint;
|
||||
IPEndPoint ipep = (IPEndPoint)ns.Connection.LocalEndPoint;
|
||||
|
||||
IPAddress localAddress = ipep.Address;
|
||||
int localPort = ipep.Port;
|
||||
|
||||
if (IsPrivateNetwork(localAddress))
|
||||
{
|
||||
ipep = (IPEndPoint)s.RemoteEndPoint;
|
||||
ipep = (IPEndPoint)ns.Connection.RemoteEndPoint;
|
||||
if (!IsPrivateNetwork(ipep.Address) && m_PublicAddress != null)
|
||||
localAddress = m_PublicAddress;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,10 +61,12 @@
|
|||
<ProjectReference Include="..\Server\Server.csproj" Private="false" PrivateAssets="All" IncludeAssets="None">
|
||||
<IncludeInPackage>false</IncludeInPackage>
|
||||
</ProjectReference>
|
||||
<PackageReference Include="MailKit" Version="2.6.0" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.4" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.4" />
|
||||
<!-- Transient package version resolution -->
|
||||
<PackageReference Include="Microsoft.AspNetCore.Connections.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.DependencyInjection.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Hosting.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="3.1.5" />
|
||||
<PackageReference Include="MailKit" Version="2.7.0" />
|
||||
<PackageReference Include="Argon2.Bindings" Version="1.2.7" />
|
||||
<PackageReference Include="Zlib.Bindings" Version="1.0.2" />
|
||||
</ItemGroup>
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue