#region References using Server.Commands.Generic; using Server.Engines.BulkOrders; using Server.Items; using Server.Network; using System; using System.Collections; using System.Collections.Generic; using System.IO; using System.Linq; using System.Reflection; using System.Text; #endregion namespace Server.Commands { public class Docs { public static void Initialize() { CommandSystem.Register("DocGen", AccessLevel.Administrator, DocGen_OnCommand); } [Usage("DocGen")] [Description("Generates ServUO documentation.")] private static void DocGen_OnCommand(CommandEventArgs e) { World.Broadcast(0x35, true, "Documentation is being generated, please wait."); Console.WriteLine("Documentation is being generated, please wait."); NetState.FlushAll(); NetState.Pause(); DateTime startTime = DateTime.UtcNow; bool generated = Document(); DateTime endTime = DateTime.UtcNow; NetState.Resume(); if (generated) { World.Broadcast( 0x35, true, "Documentation has been completed. The entire process took {0:F1} seconds.", (endTime - startTime).TotalSeconds); Console.WriteLine("Documentation complete."); } else { World.Broadcast( 0x35, true, "Docmentation failed: Documentation directories are locked and in use. Please close all open files and directories and try again."); Console.WriteLine("Documentation failed."); } } private class MemberComparer : IComparer { public int Compare(object x, object y) { if (x == y) { return 0; } ConstructorInfo aCtor = x as ConstructorInfo; ConstructorInfo bCtor = y as ConstructorInfo; PropertyInfo aProp = x as PropertyInfo; PropertyInfo bProp = y as PropertyInfo; MethodInfo aMethod = x as MethodInfo; MethodInfo bMethod = y as MethodInfo; bool aStatic = GetStaticFor(aCtor, aProp, aMethod); bool bStatic = GetStaticFor(bCtor, bProp, bMethod); if (aStatic && !bStatic) { return -1; } if (!aStatic && bStatic) { return 1; } int v = 0; if (aCtor != null) { if (bCtor == null) { v = -1; } } else if (bCtor != null) { v = 1; } else if (aProp != null) { if (bProp == null) { v = -1; } } else if (bProp != null) { v = 1; } if (v == 0) { v = string.Compare( GetNameFrom(aCtor, aProp, aMethod), GetNameFrom(bCtor, bProp, bMethod), StringComparison.Ordinal); } if (v == 0 && aCtor != null && bCtor != null) { v = aCtor.GetParameters().Length.CompareTo(bCtor.GetParameters().Length); } else if (v == 0 && aMethod != null && bMethod != null) { v = aMethod.GetParameters().Length.CompareTo(bMethod.GetParameters().Length); } return v; } private static bool GetStaticFor(ConstructorInfo ctor, PropertyInfo prop, MethodInfo method) { if (ctor != null) { return ctor.IsStatic; } if (method != null) { return method.IsStatic; } if (prop != null) { MethodInfo getMethod = prop.GetGetMethod(); MethodInfo setMethod = prop.GetGetMethod(); return (getMethod != null && getMethod.IsStatic) || (setMethod != null && setMethod.IsStatic); } return false; } private static string GetNameFrom(ConstructorInfo ctor, PropertyInfo prop, MethodInfo method) { if (ctor != null) { if (ctor.DeclaringType != null) { return ctor.DeclaringType.Name; } return ctor.Name; } if (prop != null) { return prop.Name; } if (method != null) { return method.Name; } return ""; } } private class TypeComparer : IComparer { public int Compare(TypeInfo x, TypeInfo y) { if (x == null && y == null) { return 0; } if (x == null) { return -1; } if (y == null) { return 1; } return string.Compare(x.TypeName, y.TypeName, StringComparison.Ordinal); } } private class TypeInfo { public readonly Type m_Type; public readonly Type m_BaseType; public readonly Type m_Declaring; public List m_Derived, m_Nested; public readonly Type[] m_Interfaces; private readonly string m_FileName; private readonly string m_TypeName; private readonly string m_LinkName; public TypeInfo(Type type) { m_Type = type; m_BaseType = type.BaseType; m_Declaring = type.DeclaringType; m_Interfaces = type.GetInterfaces(); FormatGeneric(m_Type, out m_TypeName, out m_FileName, out m_LinkName); // Console.WriteLine( ">> inline typeinfo: "+m_TypeName ); // m_TypeName = GetGenericTypeName( m_Type ); // m_FileName = Docs.GetFileName( "docs/types/", GetGenericTypeName( m_Type, "-", "-" ), ".html" ); // m_Writer = Docs.GetWriter( "docs/types/", m_FileName ); } public string FileName => m_FileName; public string TypeName => m_TypeName; public string LinkName(string dirRoot) { return m_LinkName.Replace("@directory@", dirRoot); } } #region FileSystem private static readonly char[] ReplaceChars = "<>".ToCharArray(); public static string GetFileName(string root, string name, string ext) { if (name.IndexOfAny(ReplaceChars) >= 0) { StringBuilder sb = new StringBuilder(name); foreach (char c in ReplaceChars) { sb.Replace(c, '-'); } name = sb.ToString(); } int index = 0; string file = string.Concat(name, ext); while (File.Exists(Path.Combine(root, file))) { file = string.Concat(name, ++index, ext); } return file; } private static readonly string m_RootDirectory = Path.GetDirectoryName(Environment.GetCommandLineArgs()[0]); private static void EnsureDirectory(string path) { path = Path.Combine(m_RootDirectory, path); if (!Directory.Exists(path)) { Directory.CreateDirectory(path); } } private static void DeleteDirectory(string path) { path = Path.Combine(m_RootDirectory, path); if (Directory.Exists(path)) { Directory.Delete(path, true); } } private static StreamWriter GetWriter(string root, string name) { return new StreamWriter(Path.Combine(Path.Combine(m_RootDirectory, root), name)); } private static StreamWriter GetWriter(string path) { return new StreamWriter(Path.Combine(m_RootDirectory, path)); } #endregion #region GetPair private static readonly string[,] m_Aliases = { {"System.Object", "object"}, {"System.String", "string"}, {"System.Boolean", "bool"}, {"System.Byte", "byte"}, {"System.SByte", "sbyte"}, {"System.Int16", "short"}, {"System.UInt16", "ushort"}, {"System.Int32", "int"}, {"System.UInt32", "uint"}, {"System.Int64", "long"}, {"System.UInt64", "ulong"}, {"System.Single", "float"}, {"System.Double", "double"}, {"System.Decimal", "decimal"}, {"System.Char", "char"}, {"System.Void", "void"} }; private static readonly int m_AliasLength = m_Aliases.GetLength(0); public static string GetPair(Type varType, string name, bool ignoreRef) { string prepend = ""; StringBuilder append = new StringBuilder(); Type realType = varType; if (varType.IsByRef) { if (!ignoreRef) { prepend = RefString; } realType = varType.GetElementType(); } if (realType.IsPointer) { if (realType.IsArray) { append.Append('*'); do { append.Append('['); for (int i = 1; i < realType.GetArrayRank(); ++i) { append.Append(','); } append.Append(']'); realType = realType.GetElementType(); } while (realType.IsArray); append.Append(' '); } else { realType = realType.GetElementType(); append.Append(" *"); } } else if (realType.IsArray) { do { append.Append('['); for (int i = 1; i < realType.GetArrayRank(); ++i) { append.Append(','); } append.Append(']'); realType = realType.GetElementType(); } while (realType.IsArray); append.Append(' '); } else { append.Append(' '); } string fullName = realType.FullName; string aliased = null; // = realType.Name; TypeInfo info = null; m_Types.TryGetValue(realType, out info); if (info != null) { aliased = "" + info.LinkName(null); //aliased = String.Format( "{1}", info.m_FileName, info.m_TypeName ); } else { //FormatGeneric( ); if (realType.IsGenericType) { string typeName, fileName, linkName; FormatGeneric(realType, out typeName, out fileName, out linkName); linkName = linkName.Replace("@directory@", null); aliased = linkName; } else { for (int i = 0; i < m_AliasLength; ++i) { if (m_Aliases[i, 0] == fullName) { aliased = m_Aliases[i, 1]; break; } } } if (aliased == null) { aliased = realType.Name; } } string retval = string.Concat(prepend, aliased, append, name); //Console.WriteLine(">> getpair: "+retval); return retval; } #endregion private static Dictionary m_Types; private static Dictionary> m_Namespaces; #region Root documentation private static bool Document() { try { DeleteDirectory("docs/"); } catch (Exception e) { Diagnostics.ExceptionLogging.LogException(e); return false; } EnsureDirectory("docs/"); EnsureDirectory("docs/namespaces/"); EnsureDirectory("docs/types/"); EnsureDirectory("docs/bods/"); GenerateStyles(); GenerateIndex(); DocumentCommands(); DocumentKeywords(); DocumentBodies(); if (!BulkOrderSystem.NewSystemEnabled) { DocumentBulkOrders(); } m_Types = new Dictionary(); m_Namespaces = new Dictionary>(); List assemblies = new List { Core.Assembly }; assemblies.AddRange(ScriptCompiler.Assemblies); Assembly[] asms = assemblies.ToArray(); foreach (Assembly a in asms) { LoadTypes(a, asms); } DocumentLoadedTypes(); DocumentConstructableObjects(); return true; } private static void AddIndexLink(StreamWriter html, string filePath, string label, string desc) { html.WriteLine("

{2}

", filePath, desc, label); } private static void GenerateStyles() { using (StreamWriter css = GetWriter("docs/", "styles.css")) { css.WriteLine("body { background-color: #FFFFFF; font-family: verdana, arial; font-size: 11px; }"); css.WriteLine("a { color: #28435E; }"); css.WriteLine("a:hover { color: #4878A9; }"); css.WriteLine("td.header { background-color: #9696AA; font-weight: bold; font-size: 12px; }"); css.WriteLine("td.lentry { background-color: #D7D7EB; width: 10%; }"); css.WriteLine("td.rentry { background-color: #FFFFFF; width: 90%; }"); css.WriteLine("td.entry { background-color: #FFFFFF; }"); css.WriteLine("td { font-size: 11px; }"); css.WriteLine(".tbl-border { background-color: #46465A; }"); css.WriteLine("td.ir {{ background-color: #{0:X6}; }}", Iron); css.WriteLine("td.du {{ background-color: #{0:X6}; }}", DullCopper); css.WriteLine("td.sh {{ background-color: #{0:X6}; }}", ShadowIron); css.WriteLine("td.co {{ background-color: #{0:X6}; }}", Copper); css.WriteLine("td.br {{ background-color: #{0:X6}; }}", Bronze); css.WriteLine("td.go {{ background-color: #{0:X6}; }}", Gold); css.WriteLine("td.ag {{ background-color: #{0:X6}; }}", Agapite); css.WriteLine("td.ve {{ background-color: #{0:X6}; }}", Verite); css.WriteLine("td.va {{ background-color: #{0:X6}; }}", Valorite); css.WriteLine("td.cl {{ background-color: #{0:X6}; }}", Cloth); css.WriteLine("td.pl {{ background-color: #{0:X6}; }}", Plain); css.WriteLine("td.sp {{ background-color: #{0:X6}; }}", SpinedAOS); css.WriteLine("td.ho {{ background-color: #{0:X6}; }}", HornedAOS); css.WriteLine("td.ba {{ background-color: #{0:X6}; }}", BarbedAOS); } } private static void GenerateIndex() { using (StreamWriter html = GetWriter("docs/", "index.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Index"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); AddIndexLink( html, "commands.html", "Commands", "Every available command. This contains command name, usage, aliases, and description."); AddIndexLink( html, "objects.html", "Constructable Objects", "Every constructable item or npc. This contains object name and usage. Hover mouse over parameters to see type description."); AddIndexLink( html, "keywords.html", "Speech Keywords", "Lists speech keyword numbers and associated match patterns. These are used in some scripts for multi-language matching of client speech."); AddIndexLink( html, "bodies.html", "Body List", "Every usable body number and name. Table is generated from a UO:3D client datafile. If you do not have UO:3D installed, this may be blank."); AddIndexLink( html, "overview.html", "Class Overview", "Scripting reference. Contains every class type and contained methods in the core and scripts."); AddIndexLink( html, "bods/bod_smith_rewards.html", "Bulk Order Rewards: Smithing", "Reference table for large and small smithing bulk order deed rewards."); AddIndexLink( html, "bods/bod_tailor_rewards.html", "Bulk Order Rewards: Tailoring", "Reference table for large and small tailoring bulk order deed rewards."); html.WriteLine(" "); html.WriteLine(""); } } #endregion #region BODs private const int Iron = 0xCCCCDD; private const int DullCopper = 0xAAAAAA; private const int ShadowIron = 0x777799; private const int Copper = 0xDDCC99; private const int Bronze = 0xAA8866; private const int Gold = 0xDDCC55; private const int Agapite = 0xDDAAAA; private const int Verite = 0x99CC77; private const int Valorite = 0x88AABB; private const int Cloth = 0xDDDDDD; private const int Plain = 0xCCAA88; private const int SpinedAOS = 0x99BBBB; private const int HornedAOS = 0xCC8888; private const int BarbedAOS = 0xAABBAA; private const int SpinedLBR = 0xAA8833; private const int HornedLBR = 0xBBBBAA; private const int BarbedLBR = 0xCCAA88; private static void DocumentBulkOrders() { using (StreamWriter html = GetWriter("docs/bods/", "bod_smith_rewards.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Bulk Orders - Smith Rewards"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); SmallBOD sbod = new SmallSmithBOD { Type = typeof(Katana), Material = BulkMaterialType.None, AmountMax = 10 }; WriteSmithBODHeader(html, "(Small) Weapons"); sbod.RequireExceptional = false; DocumentSmithBOD(html, sbod.ComputeRewards(true), "10, 15, 20: Normal", sbod.Material); sbod.RequireExceptional = true; DocumentSmithBOD(html, sbod.ComputeRewards(true), "10, 15, 20: Exceptional", sbod.Material); WriteSmithBODFooter(html); html.WriteLine("

"); html.WriteLine("

"); sbod.Type = typeof(PlateArms); WriteSmithBODHeader(html, "(Small) Armor: Normal"); sbod.RequireExceptional = false; for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat) { sbod.Material = mat; sbod.AmountMax = 10; DocumentSmithBOD(html, sbod.ComputeRewards(true), "10, 15, 20", sbod.Material); } WriteSmithBODFooter(html); html.WriteLine("

"); WriteSmithBODHeader(html, "(Small) Armor: Exceptional"); sbod.RequireExceptional = true; for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat) { sbod.Material = mat; for (int amt = 15; amt <= 20; amt += 5) { sbod.AmountMax = amt; DocumentSmithBOD(html, sbod.ComputeRewards(true), amt == 20 ? "20" : "10, 15", sbod.Material); } } WriteSmithBODFooter(html); html.WriteLine("

"); html.WriteLine("

"); sbod.Delete(); WriteSmithLBOD(html, "Ringmail", LargeBulkEntry.LargeRing); WriteSmithLBOD(html, "Chainmail", LargeBulkEntry.LargeChain); WriteSmithLBOD(html, "Platemail", LargeBulkEntry.LargePlate); html.WriteLine(" "); html.WriteLine(""); } using (StreamWriter html = GetWriter("docs/bods/", "bod_tailor_rewards.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Bulk Orders - Tailor Rewards"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); SmallBOD sbod = new SmallTailorBOD(); WriteTailorBODHeader(html, "Small Bulk Order"); html.WriteLine(" "); html.WriteLine(" Regular: 10, 15"); html.WriteLine(" "); sbod.AmountMax = 10; sbod.RequireExceptional = false; sbod.Type = typeof(SkullCap); sbod.Material = BulkMaterialType.None; DocumentTailorBOD(html, sbod.ComputeRewards(true), "10, 15", sbod.Material, sbod.Type); sbod.Type = typeof(LeatherCap); for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat) { if (mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite) { continue; } sbod.Material = mat; DocumentTailorBOD(html, sbod.ComputeRewards(true), "10, 15", sbod.Material, sbod.Type); } html.WriteLine(" "); html.WriteLine(" Regular: 20"); html.WriteLine(" "); sbod.AmountMax = 20; sbod.RequireExceptional = false; sbod.Type = typeof(SkullCap); sbod.Material = BulkMaterialType.None; DocumentTailorBOD(html, sbod.ComputeRewards(true), "20", sbod.Material, sbod.Type); sbod.Type = typeof(LeatherCap); for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat) { if (mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite) { continue; } sbod.Material = mat; DocumentTailorBOD(html, sbod.ComputeRewards(true), "20", sbod.Material, sbod.Type); } html.WriteLine(" "); html.WriteLine( " Exceptional: 10, 15"); html.WriteLine(" "); sbod.AmountMax = 10; sbod.RequireExceptional = true; sbod.Type = typeof(SkullCap); sbod.Material = BulkMaterialType.None; DocumentTailorBOD(html, sbod.ComputeRewards(true), "10, 15", sbod.Material, sbod.Type); sbod.Type = typeof(LeatherCap); for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat) { if (mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite) { continue; } sbod.Material = mat; DocumentTailorBOD(html, sbod.ComputeRewards(true), "10, 15", sbod.Material, sbod.Type); } html.WriteLine(" "); html.WriteLine(" Exceptional: 20"); html.WriteLine(" "); sbod.AmountMax = 20; sbod.RequireExceptional = true; sbod.Type = typeof(SkullCap); sbod.Material = BulkMaterialType.None; DocumentTailorBOD(html, sbod.ComputeRewards(true), "20", sbod.Material, sbod.Type); sbod.Type = typeof(LeatherCap); for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Barbed; ++mat) { if (mat >= BulkMaterialType.DullCopper && mat <= BulkMaterialType.Valorite) { continue; } sbod.Material = mat; DocumentTailorBOD(html, sbod.ComputeRewards(true), "20", sbod.Material, sbod.Type); } WriteTailorBODFooter(html); html.WriteLine("

"); html.WriteLine("

"); sbod.Delete(); WriteTailorLBOD(html, "Large Bulk Order: 4-part", LargeBulkEntry.Gypsy, true, true); WriteTailorLBOD(html, "Large Bulk Order: 5-part", LargeBulkEntry.TownCrier, true, true); WriteTailorLBOD(html, "Large Bulk Order: 6-part", LargeBulkEntry.MaleLeatherSet, false, true); html.WriteLine(" "); html.WriteLine(""); } } #region Tailor Bods private static void WriteTailorLBOD( StreamWriter html, string name, SmallBulkEntry[] entries, bool expandCloth, bool expandPlain) { WriteTailorBODHeader(html, name); LargeBOD lbod = new LargeTailorBOD(); lbod.Entries = LargeBulkEntry.ConvertEntries(lbod, entries); Type type = entries[0].Type; bool showCloth = !(type.IsSubclassOf(typeof(BaseArmor)) || type.IsSubclassOf(typeof(BaseShoes))); html.WriteLine(" "); html.WriteLine(" Regular"); html.WriteLine(" "); lbod.RequireExceptional = false; lbod.AmountMax = 10; if (showCloth) { lbod.Material = BulkMaterialType.None; if (expandCloth) { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15", lbod.Material, type); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, type); } else { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, type); } } lbod.Material = BulkMaterialType.None; if (expandPlain) { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, typeof(LeatherCap)); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, typeof(LeatherCap)); } else { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, typeof(LeatherCap)); } for (BulkMaterialType mat = BulkMaterialType.Spined; mat <= BulkMaterialType.Barbed; ++mat) { lbod.Material = mat; lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15", lbod.Material, type); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, type); } html.WriteLine(" "); html.WriteLine(" Exceptional"); html.WriteLine(" "); lbod.RequireExceptional = true; lbod.AmountMax = 10; if (showCloth) { lbod.Material = BulkMaterialType.None; if (expandCloth) { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15", lbod.Material, type); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, type); } else { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, type); } } lbod.Material = BulkMaterialType.None; if (expandPlain) { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, typeof(LeatherCap)); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, typeof(LeatherCap)); } else { lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material, typeof(LeatherCap)); } for (BulkMaterialType mat = BulkMaterialType.Spined; mat <= BulkMaterialType.Barbed; ++mat) { lbod.Material = mat; lbod.AmountMax = 10; DocumentTailorBOD(html, lbod.ComputeRewards(true), "10, 15", lbod.Material, type); lbod.AmountMax = 20; DocumentTailorBOD(html, lbod.ComputeRewards(true), "20", lbod.Material, type); } WriteTailorBODFooter(html); html.WriteLine("

"); html.WriteLine("

"); } private static void WriteTailorBODHeader(StreamWriter html, string title) { html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " ", title); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); } private static void WriteTailorBODFooter(StreamWriter html) { html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine("
{0}
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
Power Scrolls
\"Small
\"Medium
\"Light
\"Dark
\"Brown
\"Polar
\"Clothing
Runic Kits
+5
+10
+15
+20
\"Runic
\"Runic
\"Runic
 
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
\"Colored
+5
+10
+15
+20
\"Small
\"Medium
\"Light
\"Dark
\"Brown
\"Polar
\"Clothing
\"Runic
\"Runic
\"Runic
Power Scrolls
Runic Kits
"); } private static void DocumentTailorBOD( StreamWriter html, IEnumerable items, string amt, BulkMaterialType material, Type type) { bool[] rewards = new bool[20]; foreach (Item item in items) { if (item is Sandals) { rewards[5] = true; } else if (item is SmallStretchedHideEastDeed || item is SmallStretchedHideSouthDeed) { rewards[10] = rewards[11] = true; } else if (item is MediumStretchedHideEastDeed || item is MediumStretchedHideSouthDeed) { rewards[10] = rewards[11] = true; } else if (item is LightFlowerTapestryEastDeed || item is LightFlowerTapestrySouthDeed) { rewards[12] = rewards[13] = true; } else if (item is DarkFlowerTapestryEastDeed || item is DarkFlowerTapestrySouthDeed) { rewards[12] = rewards[13] = true; } else if (item is BrownBearRugEastDeed || item is BrownBearRugSouthDeed) { rewards[14] = rewards[15] = true; } else if (item is PolarBearRugEastDeed || item is PolarBearRugSouthDeed) { rewards[14] = rewards[15] = true; } else if (item is ClothingBlessDeed) { rewards[16] = true; } else if (item is PowerScroll) { PowerScroll ps = (PowerScroll)item; if (ps.Value == 105.0) { rewards[6] = true; } else if (ps.Value == 110.0) { rewards[7] = true; } else if (ps.Value == 115.0) { rewards[8] = true; } else if (ps.Value == 120.0) { rewards[9] = true; } } else if (item is UncutCloth) { if (item.Hue == 0x483 || item.Hue == 0x48C || item.Hue == 0x488 || item.Hue == 0x48A) { rewards[0] = true; } else if (item.Hue == 0x495 || item.Hue == 0x48B || item.Hue == 0x486 || item.Hue == 0x485) { rewards[1] = true; } else if (item.Hue == 0x48D || item.Hue == 0x490 || item.Hue == 0x48E || item.Hue == 0x491) { rewards[2] = true; } else if (item.Hue == 0x48F || item.Hue == 0x494 || item.Hue == 0x484 || item.Hue == 0x497) { rewards[3] = true; } else { rewards[4] = true; } } else if (item is RunicSewingKit) { RunicSewingKit rkit = (RunicSewingKit)item; rewards[16 + CraftResources.GetIndex(rkit.Resource)] = true; } item.Delete(); } string style = null; string name = null; switch (material) { case BulkMaterialType.None: { if (type.IsSubclassOf(typeof(BaseArmor)) || type.IsSubclassOf(typeof(BaseShoes))) { style = "pl"; name = "Plain"; } else { style = "cl"; name = "Cloth"; } break; } case BulkMaterialType.Spined: style = "sp"; name = "Spined"; break; case BulkMaterialType.Horned: style = "ho"; name = "Horned"; break; case BulkMaterialType.Barbed: style = "ba"; name = "Barbed"; break; } html.WriteLine(" "); html.WriteLine( "  - {0} {1}", name, amt); int index = 0; while (index < 20) { if (rewards[index]) { html.WriteLine("
X
", style); ++index; } else { int count = 0; while (index < 20 && !rewards[index]) { ++count; ++index; if (index == 5 || index == 6 || index == 10 || index == 17) { break; } } html.WriteLine( "  ", count * 25, count == 1 ? "" : string.Format(" colspan=\"{0}\"", count)); } } html.WriteLine(" "); } #endregion #region Smith Bods private static void WriteSmithLBOD(StreamWriter html, string name, SmallBulkEntry[] entries) { LargeBOD lbod = new LargeSmithBOD(); lbod.Entries = LargeBulkEntry.ConvertEntries(lbod, entries); WriteSmithBODHeader(html, string.Format("(Large) {0}: Normal", name)); lbod.RequireExceptional = false; for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat) { lbod.Material = mat; lbod.AmountMax = 10; DocumentSmithBOD(html, lbod.ComputeRewards(true), "10, 15, 20", lbod.Material); } WriteSmithBODFooter(html); html.WriteLine("

"); WriteSmithBODHeader(html, string.Format("(Large) {0}: Exceptional", name)); lbod.RequireExceptional = true; for (BulkMaterialType mat = BulkMaterialType.None; mat <= BulkMaterialType.Valorite; ++mat) { lbod.Material = mat; for (int amt = 15; amt <= 20; amt += 5) { lbod.AmountMax = amt; DocumentSmithBOD(html, lbod.ComputeRewards(true), amt == 20 ? "20" : "10, 15", lbod.Material); } } WriteSmithBODFooter(html); html.WriteLine("

"); html.WriteLine("

"); } private static void WriteSmithBODHeader(StreamWriter html, string title) { html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " ", title); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); } private static void WriteSmithBODFooter(StreamWriter html) { html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine( " "); html.WriteLine(" "); html.WriteLine("
{0}
\"Sturdy
Gloves
\"Gargoyles
\"Prospectors
\"Powder
\"Colored
Power Scrolls
Runic Hammers
Ancient Hammers
+1
+3
+5
+5
+10
+15
+20
Du
Sh
Co
Br
Go
Ag
Ve
Va
+10
+15
+30
+60
 
\"Sturdy
+1
 
+3
 
+5
 
\"Gargoyles
\"Prospectors
\"Powder
\"Colored
+5
+10
+15
+20
Du
Sh
Co
Br
Go
Ag
Ve
Va
+10
+15
+30
+60
Gloves
Power Scrolls
Runic Hammers
Ancient Hammers
"); } private static void DocumentSmithBOD( StreamWriter html, IEnumerable items, string amt, BulkMaterialType material) { bool[] rewards = new bool[24]; foreach (Item item in items) { if (item is SturdyPickaxe || item is SturdyShovel) { rewards[0] = true; } else if (item is LeatherGlovesOfMining) { rewards[1] = true; } else if (item is StuddedGlovesOfMining) { rewards[2] = true; } else if (item is RingmailGlovesOfMining) { rewards[3] = true; } else if (item is GargoylesPickaxe) { rewards[4] = true; } else if (item is ProspectorsTool) { rewards[5] = true; } else if (item is PowderOfTemperament) { rewards[6] = true; } else if (item is ColoredAnvil) { rewards[7] = true; } else if (item is PowerScroll) { PowerScroll ps = (PowerScroll)item; if (ps.Value == 105.0) { rewards[8] = true; } else if (ps.Value == 110.0) { rewards[9] = true; } else if (ps.Value == 115.0) { rewards[10] = true; } else if (ps.Value == 120.0) { rewards[11] = true; } } else if (item is RunicHammer) { RunicHammer rh = (RunicHammer)item; rewards[11 + CraftResources.GetIndex(rh.Resource)] = true; } else if (item is AncientSmithyHammer) { AncientSmithyHammer ash = (AncientSmithyHammer)item; if (ash.Bonus == 10) { rewards[20] = true; } else if (ash.Bonus == 15) { rewards[21] = true; } else if (ash.Bonus == 30) { rewards[22] = true; } else if (ash.Bonus == 60) { rewards[23] = true; } } item.Delete(); } string style = null; string name = null; switch (material) { case BulkMaterialType.None: style = "ir"; name = "Iron"; break; case BulkMaterialType.DullCopper: style = "du"; name = "Dull Copper"; break; case BulkMaterialType.ShadowIron: style = "sh"; name = "Shadow Iron"; break; case BulkMaterialType.Copper: style = "co"; name = "Copper"; break; case BulkMaterialType.Bronze: style = "br"; name = "Bronze"; break; case BulkMaterialType.Gold: style = "go"; name = "Gold"; break; case BulkMaterialType.Agapite: style = "ag"; name = "Agapite"; break; case BulkMaterialType.Verite: style = "ve"; name = "Verite"; break; case BulkMaterialType.Valorite: style = "va"; name = "Valorite"; break; } html.WriteLine(" "); html.WriteLine( " {0} {1}", name, amt); int index = 0; while (index < 24) { if (rewards[index]) { html.WriteLine("
X
", style); ++index; } else { int count = 0; while (index < 24 && !rewards[index]) { ++count; ++index; if (index == 4 || index == 8 || index == 12 || index == 20) { break; } } html.WriteLine( "  ", count * 25, count == 1 ? "" : string.Format(" colspan=\"{0}\"", count)); } } html.WriteLine(" "); } #endregion #endregion #region Bodies public static List LoadBodies() { List list = new List(); string path = Path.Combine(Core.BaseDirectory, "Data/models.txt"); if (File.Exists(path)) { using (StreamReader ip = new StreamReader(path)) { string line; while ((line = ip.ReadLine()) != null) { line = line.Trim(); if (line.Length == 0 || line.StartsWith("#")) { continue; } string[] split = line.Split('\t'); if (split.Length < 3) { continue; } int body; if (!int.TryParse(split[0], out body)) { continue; } ModelBodyType type; if (!Enum.TryParse(split[1], out type)) { type = ModelBodyType.Invalid; } string name = string.Join(" ", split.Skip(2).Select(n => !string.IsNullOrWhiteSpace(n) ? n : "unknown")); BodyEntry entry = new BodyEntry(body, type, name); if (!list.Contains(entry)) { list.Add(entry); } } } } return list; } private static void DocumentBodies() { List list = LoadBodies(); using (StreamWriter html = GetWriter("docs/", "bodies.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Body List"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine("

Back to the index

"); if (list.Count > 0) { html.WriteLine("

Body List

"); list.Sort(new BodyEntrySorter()); ModelBodyType lastType = ModelBodyType.Invalid; foreach (BodyEntry entry in list) { ModelBodyType type = entry.BodyType; if (type != lastType) { if (lastType != ModelBodyType.Invalid) { html.WriteLine("
"); } lastType = type; html.WriteLine(" ", type); switch (type) { case ModelBodyType.Monsters: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

"); break; case ModelBodyType.Sea: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

"); break; case ModelBodyType.Animals: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

"); break; case ModelBodyType.Human: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

"); break; case ModelBodyType.Equipment: html.WriteLine( " Monsters | Sea | Animals | Human | Equipment

"); break; } html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" ", type); } html.WriteLine( " ", entry.Body.BodyID, entry.Name); } html.WriteLine("
{0}
{0}{1}
"); } else { html.WriteLine(" This feature requires a UO:3D installation."); } html.WriteLine(" "); html.WriteLine(""); } } #endregion #region Speech private static void DocumentKeywords() { List> tables = LoadSpeechFile(); using (StreamWriter html = GetWriter("docs/", "keywords.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Speech Keywords"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine("

Back to the index

"); html.WriteLine("

Speech Keywords

"); for (int p = 0; p < 1 && p < tables.Count; ++p) { Dictionary table = tables[p]; if (p > 0) { html.WriteLine("
"); } html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" "); List list = new List(table.Values); list.Sort(new SpeechEntrySorter()); foreach (SpeechEntry entry in list) { html.Write(" "); } html.WriteLine("
NumberText
0x{0:X4}", entry.Index); entry.Strings.Sort(); //( new EnglishPrioStringSorter() ); for (int j = 0; j < entry.Strings.Count; ++j) { if (j > 0) { html.Write("
"); } string v = entry.Strings[j]; foreach (char c in v) { switch (c) { case '<': html.Write("<"); break; case '>': html.Write(">"); break; case '&': html.Write("&"); break; case '"': html.Write("""); break; case '\'': html.Write("'"); break; default: { if (c >= 0x20 && c < 0x80) { html.Write(c); } else { html.Write("&#{0};", (int)c); } } break; } } } html.WriteLine("
"); } html.WriteLine(" "); html.WriteLine(""); } } private class SpeechEntry { private readonly int m_Index; private readonly List m_Strings; public int Index => m_Index; public List Strings => m_Strings; public SpeechEntry(int index) { m_Index = index; m_Strings = new List(); } } private class SpeechEntrySorter : IComparer { public int Compare(SpeechEntry x, SpeechEntry y) { return x.Index.CompareTo(y.Index); } } private static List> LoadSpeechFile() { List> tables = new List>(); int lastIndex = -1; Dictionary table = null; string path = Core.FindDataFile("speech.mul"); if (File.Exists(path)) { using (FileStream ip = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.Read)) { BinaryReader bin = new BinaryReader(ip); while (bin.PeekChar() >= 0) { int index = (bin.ReadByte() << 8) | bin.ReadByte(); int length = (bin.ReadByte() << 8) | bin.ReadByte(); string text = Encoding.UTF8.GetString(bin.ReadBytes(length)).Trim(); if (text.Length == 0) { continue; } if (table == null || lastIndex > index) { if (index == 0 && text == "*withdraw*") { tables.Insert(0, table = new Dictionary()); } else { tables.Add(table = new Dictionary()); } } lastIndex = index; SpeechEntry entry; table.TryGetValue(index, out entry); if (entry == null) { table[index] = entry = new SpeechEntry(index); } entry.Strings.Add(text); } } } return tables; } #endregion #region Commands public class DocCommandEntry { private readonly AccessLevel m_AccessLevel; private readonly string m_Name; private readonly string[] m_CmdAliases; private readonly string m_Usage; private readonly string m_Description; public AccessLevel AccessLevel => m_AccessLevel; public string Name => m_Name; public string[] Aliases => m_CmdAliases; public string Usage => m_Usage; public string Description => m_Description; public DocCommandEntry(AccessLevel accessLevel, string name, string[] aliases, string usage, string description) { m_AccessLevel = accessLevel; m_Name = name; m_CmdAliases = aliases; m_Usage = usage; m_Description = description; } } public class CommandEntrySorter : IComparer { public int Compare(DocCommandEntry a, DocCommandEntry b) { int v = b.AccessLevel.CompareTo(a.AccessLevel); if (v == 0) { v = string.Compare(a.Name, b.Name, StringComparison.Ordinal); } return v; } } private static void DocumentCommands() { using (StreamWriter html = GetWriter("docs/", "commands.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Commands"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine("

Back to the index

"); html.WriteLine("

Commands

"); List commands = new List(CommandSystem.Entries.Values); List list = new List(); commands.Sort(); commands.Reverse(); Clean(commands); foreach (CommandEntry e in commands) { MethodInfo mi = e.Handler.Method; object[] attrs = mi.GetCustomAttributes(typeof(UsageAttribute), false); if (attrs.Length == 0) { continue; } UsageAttribute usage = attrs[0] as UsageAttribute; attrs = mi.GetCustomAttributes(typeof(DescriptionAttribute), false); if (attrs.Length == 0) { continue; } DescriptionAttribute desc = attrs[0] as DescriptionAttribute; if (usage == null || desc == null) { continue; } attrs = mi.GetCustomAttributes(typeof(AliasesAttribute), false); AliasesAttribute aliases = (attrs.Length == 0 ? null : attrs[0] as AliasesAttribute); string descString = desc.Description.Replace("<", "<").Replace(">", ">"); list.Add( aliases == null ? new DocCommandEntry(e.AccessLevel, e.Command, null, usage.Usage, descString) : new DocCommandEntry(e.AccessLevel, e.Command, aliases.Aliases, usage.Usage, descString)); } foreach (BaseCommand command in TargetCommands.AllCommands) { string usage = command.Usage; string desc = command.Description; if (usage == null || desc == null) { continue; } string[] cmds = command.Commands; string cmd = cmds[0]; string[] aliases = new string[cmds.Length - 1]; for (int j = 0; j < aliases.Length; ++j) { aliases[j] = cmds[j + 1]; } desc = desc.Replace("<", "<").Replace(">", ">"); if (command.Supports != CommandSupport.Single) { StringBuilder sb = new StringBuilder(50 + desc.Length); sb.Append("Modifiers: "); if ((command.Supports & CommandSupport.Global) != 0) { sb.Append("Global, "); } if ((command.Supports & CommandSupport.Online) != 0) { sb.Append("Online, "); } if ((command.Supports & CommandSupport.Region) != 0) { sb.Append("Region, "); } if ((command.Supports & CommandSupport.Contained) != 0) { sb.Append("Contained, "); } if ((command.Supports & CommandSupport.Multi) != 0) { sb.Append("Multi, "); } if ((command.Supports & CommandSupport.Area) != 0) { sb.Append("Area, "); } if ((command.Supports & CommandSupport.Self) != 0) { sb.Append("Self, "); } sb.Remove(sb.Length - 2, 2); sb.Append("
"); sb.Append(desc); desc = sb.ToString(); } list.Add(new DocCommandEntry(command.AccessLevel, cmd, aliases, usage, desc)); } List commandImpls = BaseCommandImplementor.Implementors; foreach (BaseCommandImplementor command in commandImpls) { string usage = command.Usage; string desc = command.Description; if (usage == null || desc == null) { continue; } string[] cmds = command.Accessors; string cmd = cmds[0]; string[] aliases = new string[cmds.Length - 1]; for (int j = 0; j < aliases.Length; ++j) { aliases[j] = cmds[j + 1]; } desc = desc.Replace("<", "<").Replace(">", ">"); list.Add(new DocCommandEntry(command.AccessLevel, cmd, aliases, usage, desc)); } list.Sort(new CommandEntrySorter()); AccessLevel last = AccessLevel.Player; foreach (DocCommandEntry e in list) { if (e.AccessLevel != last) { if (last != AccessLevel.Player) { html.WriteLine("

"); } last = e.AccessLevel; html.WriteLine(" ", last); switch (last) { case AccessLevel.Administrator: html.WriteLine( " Administrator | Game Master | Counselor | Player

"); break; case AccessLevel.GameMaster: html.WriteLine( " Administrator | Game Master | Counselor | Player

"); break; case AccessLevel.Seer: html.WriteLine( " Administrator | Game Master | Counselor | Player

"); break; case AccessLevel.Counselor: html.WriteLine( " Administrator | Game Master | Counselor | Player

"); break; case AccessLevel.Player: html.WriteLine( " Administrator | Game Master | Counselor | Player

"); break; } html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine( " ", last == AccessLevel.GameMaster ? "Game Master" : last.ToString()); } DocumentCommand(html, e); } html.WriteLine("
{0}
"); html.WriteLine(" "); html.WriteLine(""); } } public static void Clean(List list) { for (int i = 0; i < list.Count; ++i) { CommandEntry e = list[i]; for (int j = i + 1; j < list.Count; ++j) { CommandEntry c = list[j]; if (e.Handler.Method == c.Handler.Method) { list.RemoveAt(j); --j; } } } } private static void DocumentCommand(StreamWriter html, DocCommandEntry e) { string usage = e.Usage; string desc = e.Description; string[] aliases = e.Aliases; html.Write(" {0}", e.Name); if (aliases == null || aliases.Length == 0) { html.Write( "Usage: {0}
{1}", usage.Replace("<", "<").Replace(">", ">"), desc); } else { html.Write( "Usage: {0}
Alias{1}: ", usage.Replace("<", "<").Replace(">", ">"), aliases.Length == 1 ? "" : "es"); for (int i = 0; i < aliases.Length; ++i) { if (i != 0) { html.Write(", "); } html.Write(aliases[i]); } html.Write("
{0}", desc); } html.WriteLine(""); } #endregion private static void LoadTypes(Assembly a, Assembly[] asms) { Type[] types = a.GetTypes(); foreach (Type type in types) { string nspace = type.Namespace; if (nspace == null || type.IsSpecialName) { continue; } TypeInfo info = new TypeInfo(type); m_Types[type] = info; List nspaces; m_Namespaces.TryGetValue(nspace, out nspaces); if (nspaces == null) { m_Namespaces[nspace] = nspaces = new List(); } nspaces.Add(info); Type baseType = info.m_BaseType; if (baseType != null && InAssemblies(baseType, asms)) { TypeInfo baseInfo; m_Types.TryGetValue(baseType, out baseInfo); if (baseInfo == null) { m_Types[baseType] = baseInfo = new TypeInfo(baseType); } if (baseInfo.m_Derived == null) { baseInfo.m_Derived = new List(); } baseInfo.m_Derived.Add(info); } Type decType = info.m_Declaring; if (decType != null) { TypeInfo decInfo; m_Types.TryGetValue(decType, out decInfo); if (decInfo == null) { m_Types[decType] = decInfo = new TypeInfo(decType); } if (decInfo.m_Nested == null) { decInfo.m_Nested = new List(); } decInfo.m_Nested.Add(info); } foreach (Type iface in info.m_Interfaces) { if (!InAssemblies(iface, asms)) { continue; } TypeInfo ifaceInfo = null; m_Types.TryGetValue(iface, out ifaceInfo); if (ifaceInfo == null) { m_Types[iface] = ifaceInfo = new TypeInfo(iface); } if (ifaceInfo.m_Derived == null) { ifaceInfo.m_Derived = new List(); } ifaceInfo.m_Derived.Add(info); } } } private static bool InAssemblies(Type t, IEnumerable asms) { return asms.Any(a => a == t.Assembly); } #region Constructable Objects private static readonly Type typeofItem = typeof(Item); private static readonly Type typeofMobile = typeof(Mobile); private static readonly Type typeofMap = typeof(Map); private static readonly Type typeofCustomEnum = typeof(CustomEnumAttribute); private static bool IsConstructable(Type t, out bool isItem) { isItem = typeofItem.IsAssignableFrom(t); if (isItem) { return true; } return typeofMobile.IsAssignableFrom(t); } private static bool IsConstructable(ConstructorInfo ctor) { return ctor.IsDefined(typeof(ConstructableAttribute), false); } private static void DocumentConstructableObjects() { List types = new List(m_Types.Values); types.Sort(new TypeComparer()); ArrayList items = new ArrayList(), mobiles = new ArrayList(); foreach (Type t in types.Select(ti => ti.m_Type)) { bool isItem; if (t.IsAbstract || !IsConstructable(t, out isItem)) { continue; } ConstructorInfo[] ctors = t.GetConstructors(); bool anyConstructable = false; for (int j = 0; !anyConstructable && j < ctors.Length; ++j) { anyConstructable = IsConstructable(ctors[j]); } if (!anyConstructable) { continue; } (isItem ? items : mobiles).Add(t); (isItem ? items : mobiles).Add(ctors); } using (StreamWriter html = GetWriter("docs/", "objects.html")) { html.WriteLine(""); html.WriteLine(""); html.WriteLine(" "); html.WriteLine(" RunUO Documentation - Constructable Objects"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine("

Back to the index

"); html.WriteLine("

Constructable Items and Mobiles

"); html.WriteLine(" "); html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" "); for (int i = 0; i < items.Count; i += 2) { DocumentConstructableObject(html, (Type)items[i], (ConstructorInfo[])items[i + 1]); } html.WriteLine("
Item NameUsage


"); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine("
"); html.WriteLine(" "); html.WriteLine(" "); for (int i = 0; i < mobiles.Count; i += 2) { DocumentConstructableObject(html, (Type)mobiles[i], (ConstructorInfo[])mobiles[i + 1]); } html.WriteLine("
Mobile NameUsage
"); html.WriteLine(" "); html.WriteLine(""); } } private static void DocumentConstructableObject(StreamWriter html, Type t, IEnumerable ctors) { html.Write(" {0}", t.Name); bool first = true; foreach (ConstructorInfo ctor in ctors.Where(IsConstructable)) { if (!first) { html.Write("
"); } first = false; html.Write("{0}Add {1}", CommandSystem.Prefix, t.Name); ParameterInfo[] parms = ctor.GetParameters(); foreach (ParameterInfo p in parms) { html.Write("
{1}", GetTooltipFor(p), p.Name); } } html.WriteLine(""); } #endregion #region Tooltips private const string HtmlNewLine = " "; private static readonly object[,] m_Tooltips = { {typeof(byte), "Numeric value in the range from 0 to 255, inclusive."}, {typeof(sbyte), "Numeric value in the range from negative 128 to positive 127, inclusive."}, {typeof(ushort), "Numeric value in the range from 0 to 65,535, inclusive."}, {typeof(short), "Numeric value in the range from negative 32,768 to positive 32,767, inclusive."}, {typeof(uint), "Numeric value in the range from 0 to 4,294,967,295, inclusive."}, {typeof(int), "Numeric value in the range from negative 2,147,483,648 to positive 2,147,483,647, inclusive."}, {typeof(ulong), "Numeric value in the range from 0 through about 10^20."}, {typeof(long), "Numeric value in the approximate range from negative 10^19 through 10^19."}, { typeof(string), "Text value. To specify a value containing spaces, encapsulate the value in quote characters:{0}{0}"Spaced text example"" }, {typeof(bool), "Boolean value which can be either True or False."}, {typeof(Map), "Map or facet name. Possible values include:{0}{0}- Felucca{0}- Trammel{0}- Ilshenar{0}- Malas"}, { typeof(Poison), "Poison name or level. Possible values include:{0}{0}- Lesser{0}- Regular{0}- Greater{0}- Deadly{0}- Lethal" }, { typeof(Point3D), "Three-dimensional coordinate value. Format as follows:{0}{0}"(, , )"" } }; private static string GetTooltipFor(ParameterInfo param) { Type paramType = param.ParameterType; for (int i = 0; i < m_Tooltips.GetLength(0); ++i) { Type checkType = (Type)m_Tooltips[i, 0]; if (paramType == checkType) { return string.Format((string)m_Tooltips[i, 1], HtmlNewLine); } } if (paramType.IsEnum) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Enumeration value or name. Possible named values include:{0}", HtmlNewLine); string[] names = Enum.GetNames(paramType); foreach (string n in names) { sb.AppendFormat("{0}- {1}", HtmlNewLine, n); } return sb.ToString(); } if (paramType.IsDefined(typeofCustomEnum, false)) { object[] attributes = paramType.GetCustomAttributes(typeofCustomEnum, false); if (attributes.Length > 0) { CustomEnumAttribute attr = attributes[0] as CustomEnumAttribute; if (attr != null) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Enumeration value or name. Possible named values include:{0}", HtmlNewLine); string[] names = attr.Names; foreach (string n in names) { sb.AppendFormat("{0}- {1}", HtmlNewLine, n); } return sb.ToString(); } } } else if (paramType == typeofMap) { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Enumeration value or name. Possible named values include:{0}", HtmlNewLine); string[] names = Map.GetMapNames(); foreach (string n in names) { sb.AppendFormat("{0}- {1}", HtmlNewLine, n); } return sb.ToString(); } return ""; } #endregion #region Const Strings private const string RefString = "ref "; private const string GetString = " get;"; private const string SetString = " set;"; private const string InString = "in "; private const string OutString = "out "; private const string VirtString = "virtual "; private const string CtorString = "(ctor) "; private const string StaticString = "(static) "; #endregion private static void DocumentLoadedTypes() { using (StreamWriter indexHtml = GetWriter("docs/", "overview.html")) { indexHtml.WriteLine(""); indexHtml.WriteLine(""); indexHtml.WriteLine(" "); indexHtml.WriteLine(" RunUO Documentation - Class Overview"); indexHtml.WriteLine(" "); indexHtml.WriteLine(" "); indexHtml.WriteLine(" "); indexHtml.WriteLine("

Back to the index

"); indexHtml.WriteLine("

Namespaces

"); SortedList> nspaces = new SortedList>(m_Namespaces); foreach (KeyValuePair> kvp in nspaces) { kvp.Value.Sort(new TypeComparer()); SaveNamespace(kvp.Key, kvp.Value, indexHtml); } indexHtml.WriteLine(" "); indexHtml.WriteLine(""); } } private static void SaveNamespace(string name, IEnumerable types, StreamWriter indexHtml) { string fileName = GetFileName("docs/namespaces/", name, ".html"); indexHtml.WriteLine(" {1}
", fileName, name); using (StreamWriter nsHtml = GetWriter("docs/namespaces/", fileName)) { nsHtml.WriteLine(""); nsHtml.WriteLine(""); nsHtml.WriteLine(" "); nsHtml.WriteLine(" RunUO Documentation - Class Overview - {0}", name); nsHtml.WriteLine(" "); nsHtml.WriteLine(" "); nsHtml.WriteLine(" "); nsHtml.WriteLine("

Back to the namespace index

"); nsHtml.WriteLine("

{0}

", name); foreach (TypeInfo t in types) { SaveType(t, nsHtml, fileName, name); } nsHtml.WriteLine(" "); nsHtml.WriteLine(""); } } private static void SaveType(TypeInfo info, StreamWriter nsHtml, string nsFileName, string nsName) { if (info.m_Declaring == null) { nsHtml.WriteLine(" " + info.LinkName("../types/") + "
"); } using (StreamWriter typeHtml = GetWriter(info.FileName)) { typeHtml.WriteLine(""); typeHtml.WriteLine(""); typeHtml.WriteLine(" "); typeHtml.WriteLine(" RunUO Documentation - Class Overview - {0}", info.TypeName); typeHtml.WriteLine(" "); typeHtml.WriteLine(" "); typeHtml.WriteLine(" "); typeHtml.WriteLine("

Back to {1}

", nsFileName, nsName); if (info.m_Type.IsEnum) { WriteEnum(info, typeHtml); } else { WriteType(info, typeHtml); } typeHtml.WriteLine(" "); typeHtml.WriteLine(""); } } #region Write[...] private static void WriteEnum(TypeInfo info, StreamWriter typeHtml) { Type type = info.m_Type; typeHtml.WriteLine("

{0} (Enum)

", info.TypeName); string[] names = Enum.GetNames(type); bool flags = type.IsDefined(typeof(FlagsAttribute), false); string format = flags ? " {0:G} = 0x{1:X}{2}
" : " {0:G} = {1:D}{2}
"; for (int i = 0; i < names.Length; ++i) { object value = Enum.Parse(type, names[i]); typeHtml.WriteLine(format, names[i], value, i < (names.Length - 1) ? "," : ""); } } private static void WriteType(TypeInfo info, StreamWriter typeHtml) { Type type = info.m_Type; typeHtml.Write("

"); Type decType = info.m_Declaring; if (decType != null) { // We are a nested type typeHtml.Write('('); TypeInfo decInfo; m_Types.TryGetValue(decType, out decInfo); typeHtml.Write(decInfo == null ? decType.Name : decInfo.LinkName(null)); typeHtml.Write(") - "); } typeHtml.Write(info.TypeName); Type[] ifaces = info.m_Interfaces; Type baseType = info.m_BaseType; int extendCount = 0; if (baseType != null && baseType != typeof(object) && baseType != typeof(ValueType) && !baseType.IsPrimitive) { typeHtml.Write(" : "); TypeInfo baseInfo; m_Types.TryGetValue(baseType, out baseInfo); if (baseInfo == null) { typeHtml.Write(baseType.Name); } else { typeHtml.Write("" + baseInfo.LinkName(null)); } ++extendCount; } if (ifaces.Length > 0) { if (extendCount == 0) { typeHtml.Write(" : "); } foreach (Type iface in ifaces) { TypeInfo ifaceInfo; m_Types.TryGetValue(iface, out ifaceInfo); if (extendCount != 0) { typeHtml.Write(", "); } ++extendCount; if (ifaceInfo == null) { string typeName, fileName, linkName; FormatGeneric(iface, out typeName, out fileName, out linkName); linkName = linkName.Replace("@directory@", null); typeHtml.Write("" + linkName); } else { typeHtml.Write("" + ifaceInfo.LinkName(null)); } } } typeHtml.WriteLine("

"); List derived = info.m_Derived; if (derived != null) { typeHtml.Write("

Derived Types: "); derived.Sort(new TypeComparer()); for (int i = 0; i < derived.Count; ++i) { TypeInfo derivedInfo = derived[i]; if (i != 0) { typeHtml.Write(", "); } //typeHtml.Write( "{1}", derivedInfo.m_FileName, derivedInfo.m_TypeName ); typeHtml.Write("" + derivedInfo.LinkName(null)); } typeHtml.WriteLine("

"); } List nested = info.m_Nested; if (nested != null) { typeHtml.Write("

Nested Types: "); nested.Sort(new TypeComparer()); for (int i = 0; i < nested.Count; ++i) { TypeInfo nestedInfo = nested[i]; if (i != 0) { typeHtml.Write(", "); } //typeHtml.Write( "{1}", nestedInfo.m_FileName, nestedInfo.m_TypeName ); typeHtml.Write("" + nestedInfo.LinkName(null)); } typeHtml.WriteLine("

"); } MemberInfo[] membs = type.GetMembers( BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.DeclaredOnly); Array.Sort(membs, new MemberComparer()); foreach (MemberInfo mi in membs) { if (mi is PropertyInfo) { WriteProperty((PropertyInfo)mi, typeHtml); } else if (mi is ConstructorInfo) { WriteCtor(info.TypeName, (ConstructorInfo)mi, typeHtml); } else if (mi is MethodInfo) { WriteMethod((MethodInfo)mi, typeHtml); } } } private static void WriteProperty(PropertyInfo pi, StreamWriter html) { html.Write(" "); MethodInfo getMethod = pi.GetGetMethod(); MethodInfo setMethod = pi.GetSetMethod(); if ((getMethod != null && getMethod.IsStatic) || (setMethod != null && setMethod.IsStatic)) { html.Write(StaticString); } html.Write(GetPair(pi.PropertyType, pi.Name, false)); html.Write('('); if (pi.CanRead) { html.Write(GetString); } if (pi.CanWrite) { html.Write(SetString); } html.WriteLine(" )
"); } private static void WriteCtor(string name, ConstructorInfo ctor, StreamWriter html) { if (ctor.IsStatic) { return; } html.Write(" "); html.Write(CtorString); html.Write(name); html.Write('('); ParameterInfo[] parms = ctor.GetParameters(); if (parms.Length > 0) { html.Write(' '); for (int i = 0; i < parms.Length; ++i) { ParameterInfo pi = parms[i]; if (i != 0) { html.Write(", "); } if (pi.IsIn) { html.Write(InString); } else if (pi.IsOut) { html.Write(OutString); } html.Write(GetPair(pi.ParameterType, pi.Name, pi.IsOut)); } html.Write(' '); } html.WriteLine(")
"); } private static void WriteMethod(MethodInfo mi, StreamWriter html) { if (mi.IsSpecialName) { return; } html.Write(" "); if (mi.IsStatic) { html.Write(StaticString); } if (mi.IsVirtual) { html.Write(VirtString); } html.Write(GetPair(mi.ReturnType, mi.Name, false)); html.Write('('); ParameterInfo[] parms = mi.GetParameters(); if (parms.Length > 0) { html.Write(' '); for (int i = 0; i < parms.Length; ++i) { ParameterInfo pi = parms[i]; if (i != 0) { html.Write(", "); } if (pi.IsIn) { html.Write(InString); } else if (pi.IsOut) { html.Write(OutString); } html.Write(GetPair(pi.ParameterType, pi.Name, pi.IsOut)); } html.Write(' '); } html.WriteLine(")
"); } #endregion public static void FormatGeneric(Type type, out string typeName, out string fileName, out string linkName) { string name = null; string fnam = null; string link = null; if (type.IsGenericType) { int index = type.Name.IndexOf('`'); if (index > 0) { string rootType = type.Name.Substring(0, index); StringBuilder nameBuilder = new StringBuilder(rootType); StringBuilder fnamBuilder = new StringBuilder("docs/types/" + SanitizeType(rootType)); StringBuilder linkBuilder = new StringBuilder( DontLink(type) ? ("" + rootType + "") : ("" + rootType + "")); nameBuilder.Append("<"); fnamBuilder.Append("-"); linkBuilder.Append("<"); Type[] typeArguments = type.GetGenericArguments(); for (int i = 0; i < typeArguments.Length; i++) { if (i != 0) { nameBuilder.Append(','); fnamBuilder.Append(','); linkBuilder.Append(','); } string sanitizedName = SanitizeType(typeArguments[i].Name); string aliasedName = AliasForName(sanitizedName); nameBuilder.Append(sanitizedName); fnamBuilder.Append("T"); if (DontLink(typeArguments[i])) //if( DontLink( typeArguments[i].Name ) ) { linkBuilder.Append("" + aliasedName + ""); } else { linkBuilder.Append("" + aliasedName + ""); } } nameBuilder.Append(">"); fnamBuilder.Append("-"); linkBuilder.Append(">"); name = nameBuilder.ToString(); fnam = fnamBuilder.ToString(); link = linkBuilder.ToString(); } } typeName = name ?? type.Name; if (fnam == null) { fileName = "docs/types/" + SanitizeType(type.Name) + ".html"; } else { fileName = fnam + ".html"; } if (link == null) { if (DontLink(type)) //if( DontLink( type.Name ) ) { linkName = "" + SanitizeType(type.Name) + ""; } else { linkName = "" + SanitizeType(type.Name) + ""; } } else { linkName = link; } //Console.WriteLine( typeName+":"+fileName+":"+linkName ); } public static string SanitizeType(string name) { bool anonymousType = name.Contains("<"); StringBuilder sb = new StringBuilder(name); foreach (char c in ReplaceChars) { sb.Replace(c, '-'); } if (anonymousType) { return "(Anonymous-Type)" + sb; } return sb.ToString(); } public static string AliasForName(string name) { for (int i = 0; i < m_AliasLength; ++i) { if (m_Aliases[i, 0] == name) { return m_Aliases[i, 1]; } } return name; } public static bool DontLink(Type type) { // MONO: type.Namespace is null/empty for generic arguments if (type.Name == "T" || string.IsNullOrEmpty(type.Namespace) || m_Namespaces == null) { return true; } if (type.Namespace.StartsWith("Server")) { return false; } return !m_Namespaces.ContainsKey(type.Namespace); } } #region BodyEntry & BodyType public enum ModelBodyType { Invalid = -1, Monsters, Sea, Animals, Human, Equipment } public class BodyEntry { public Body Body { get; private set; } public ModelBodyType BodyType { get; private set; } public string Name { get; private set; } public BodyEntry(Body body, ModelBodyType bodyType, string name) { Body = body; BodyType = bodyType; Name = name; } public override bool Equals(object obj) { BodyEntry e = (BodyEntry)obj; return (Body == e.Body && BodyType == e.BodyType && Name == e.Name); } public override int GetHashCode() { return Body.BodyID ^ (int)BodyType ^ Name.GetHashCode(); } } public class BodyEntrySorter : IComparer { public int Compare(BodyEntry a, BodyEntry b) { int v = a.BodyType.CompareTo(b.BodyType); if (v == 0) { v = a.Body.BodyID.CompareTo(b.Body.BodyID); } if (v == 0) { v = string.Compare(a.Name, b.Name, StringComparison.Ordinal); } return v; } } #endregion }