using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using BepInEx;
using BepInEx.Logging;
using DotNetGraph.Attributes;
using DotNetGraph.Compilation;
using DotNetGraph.Core;
using DotNetGraph.Extensions;
using JetBrains.Annotations;
using Jotunn.Entities;
using Jotunn.Managers;
using MonoMod.Utils;
using PrefabDependencyTree.Data;
using PrefabDependencyTree.Data.Drops;
using PrefabDependencyTree.Data.Drops.Generic;
using PrefabDependencyTree.Data.Filters;
using PrefabDependencyTree.Model;
using PrefabDependencyTree.Util;
using UnityEngine;
[assembly: AssemblyFileVersion("1.2.5")]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("PrefabDependencyTree")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("FixItFelix")]
[assembly: AssemblyProduct("PrefabDependencyTree")]
[assembly: AssemblyCopyright("Copyright 2023")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("e3243d22-4307-4008-ba36-9f326008cde5")]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: CompilationRelaxations(8)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.2.5.0")]
[module: UnverifiableCode]
namespace PrefabDependencyTree
{
[BepInPlugin("FixItFelix.PrefabDependencyTree", "PrefabDependencyTree", "1.2.5")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
internal class PrefabDependencyTreePlugin : BaseUnityPlugin
{
public const string PluginAuthor = "FixItFelix";
public const string PluginGUID = "FixItFelix.PrefabDependencyTree";
public const string PluginName = "PrefabDependencyTree";
public const string PluginVersion = "1.2.5";
private void Awake()
{
PrefabManager.OnPrefabsRegistered += DataHarvester.Initialize;
CommandManager.Instance.AddConsoleCommand((ConsoleCommand)(object)new ConsoleController());
}
}
}
namespace PrefabDependencyTree.Util
{
public class ConsoleController : ConsoleCommand
{
private const string prefabDependencyTreeCommand = "prefab_dependency_tree";
private const string printOption = "print_tree";
private const string printIncludeFilteredOption = "print_include_filtered_tree";
private const string printExcludeFilteredOption = "print_exclude_filtered_tree";
private const string debugLogAll = "debug_log_all";
private const string debugLogItemsCategories = "debug_log_items_categories";
private static readonly List<string> ItemTypeEnums = Enum.GetNames(typeof(ItemType)).ToList();
private static readonly List<ItemType> WeaponsAndArmorEnums = new List<ItemType>
{
(ItemType)9,
(ItemType)4,
(ItemType)7,
(ItemType)10,
(ItemType)12,
(ItemType)6,
(ItemType)11,
(ItemType)5,
(ItemType)17,
(ItemType)19,
(ItemType)15,
(ItemType)18,
(ItemType)20,
(ItemType)23,
(ItemType)3,
(ItemType)14,
(ItemType)22
};
private static readonly List<string> WeaponsAndArmorTypes = WeaponsAndArmorEnums.Select((ItemType enumEntry) => ((object)(ItemType)(ref enumEntry)).ToString()).ToList();
private const string WeaponsAndArmorTypesName = "WeaponsAndArmorTypes";
public override string Name => "prefab_dependency_tree";
public override string Help => "Prefab Dependency Tree Console Commands";
private static List<string> ReplaceTypes(List<string> input)
{
if (!input.Contains("WeaponsAndArmorTypes"))
{
return input;
}
input.Remove("WeaponsAndArmorTypes");
input.AddRange(WeaponsAndArmorTypes);
return input;
}
public override void Run(string[] args)
{
Logger.LogInfo("called '" + ((ConsoleCommand)this).Name + "' with args '" + string.Join(" ", args) + "'");
if (args.Length != 0)
{
switch (args[0])
{
case "print_tree":
WriteGraphOutput(new UnfilteredData());
break;
case "print_include_filtered_tree":
if (args.Length > 1)
{
WriteGraphOutput(new IncludeFilterTypes(ReplaceTypes(args[1].Split(new char[1] { ',' }).ToList())));
}
else
{
Logger.LogWarning("you did not provide item types to filter for, see usage");
LogUsage();
}
break;
case "print_exclude_filtered_tree":
if (args.Length > 1)
{
WriteGraphOutput(new ExcludeFilterTypes(ReplaceTypes(args[1].Split(new char[1] { ',' }).ToList())));
}
else
{
Logger.LogWarning("you did not provide item types to filter for, see usage");
LogUsage();
}
break;
case "debug_log_items_categories":
{
List<string> values = DataHarvester.LogAllItemsToCategorizedYaml();
string text2 = Path.Combine(Paths.ConfigPath, "FixItFelix.PrefabDependencyTree.all.items.categories.yaml");
File.WriteAllText(text2, string.Join("\n", values));
Logger.LogInfo("wrote file '" + text2 + "'");
break;
}
case "debug_log_all":
{
List<string> list = DataHarvester.LogAllToString();
list.ForEach(Logger.LogWarning);
string text = Path.Combine(Paths.ConfigPath, "FixItFelix.PrefabDependencyTree.all.txt");
File.WriteAllText(text, string.Join("\n", list));
Logger.LogInfo("wrote file '" + text + "'");
break;
}
default:
Logger.LogWarning("this option '" + args[0] + "' is not supported, see usage");
LogUsage();
break;
}
}
else
{
LogUsage();
}
}
private static async void WriteGraphOutput(FilteredData filteredData)
{
using StringWriter writer = new StringWriter();
CompilationContext context = new CompilationContext(writer, new CompilationOptions());
filteredData.LogOverview();
await filteredData.CreateGraph().CompileAsync(context);
string text = Path.Combine(Paths.ConfigPath, "FixItFelix.PrefabDependencyTree.graph.dot");
File.WriteAllText(text, writer.GetStringBuilder().ToString());
Logger.LogInfo("wrote graph file '" + text + "'");
RunGraphVizConverter(text);
}
private static void RunGraphVizConverter(string filePath)
{
string text = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Graphviz\\bin\\gv2gml.exe");
if (!File.Exists(text))
{
return;
}
Logger.LogInfo("GraphViz installation binary detected at '" + text + "'");
try
{
string text2 = filePath.Replace(".dot", ".gml");
Process.Start(text, "\"" + filePath + "\" -o \"" + text2 + "\"")?.WaitForExit(100000);
if (File.Exists(text2))
{
Logger.LogInfo("converted to GraphViz file to '" + text2 + "'");
}
else
{
Logger.LogWarning("converted file was not found as expected");
}
}
catch (Exception ex)
{
Logger.LogWarning("error converting .dot file using GraphViz: " + ex.Message);
}
}
private static void LogUsage()
{
Logger.LogInfo(" - prefab_dependency_tree usage - ");
Logger.LogInfo("command option:");
Logger.LogInfo(" print_tree -> will print the whole tree analyzed from game data");
Logger.LogInfo(" debug_log_all -> will log warn all prefabs (this will be huge log output!)");
Logger.LogInfo(" debug_log_items_categories -> writes all item prefabs by category into a yaml format file");
Logger.LogInfo(" print_include_filtered_tree Material,Consumable -> print tree with items of the provided item types included (complete tree with link to any included items)");
Logger.LogInfo(" print_exclude_filtered_tree Ammo,OneHandedWeapon -> print tree with items of the provided item types excluded (remove the provided types from tree)");
Logger.LogInfo(" all item types: " + string.Join(", ", ItemTypeEnums) + ", WeaponsAndArmorTypes");
}
public override List<string> CommandOptionList()
{
return new List<string> { "print_tree", "print_include_filtered_tree", "print_exclude_filtered_tree", "debug_log_all", "debug_log_items_categories" };
}
}
public static class Logger
{
private static readonly ManualLogSource LoggerInstance = Logger.CreateLogSource("PrefabDependencyTree");
public static void LogDebug(string text)
{
LoggerInstance.LogDebug((object)text);
}
public static void LogInfo(string text)
{
LoggerInstance.LogInfo((object)text);
}
public static void LogWarning(string text)
{
LoggerInstance.LogWarning((object)text);
}
public static void LogError(string text)
{
LoggerInstance.LogError((object)text);
}
}
}
namespace PrefabDependencyTree.Model
{
public class BaseCrafting
{
public readonly string Name;
public readonly Dictionary<string, GraphRecipe> Recipes = new Dictionary<string, GraphRecipe>();
protected BaseCrafting(string name)
{
Name = name;
}
protected BaseCrafting(string name, Dictionary<string, GraphRecipe> recipes)
{
Name = name;
Recipes = recipes;
}
public bool ContainsItemTypes(List<string> itemTypes)
{
return Recipes.Any((KeyValuePair<string, GraphRecipe> recipe) => itemTypes.Contains(recipe.Value.CraftedItem.Item1.ItemType) || recipe.Value.RequiredItems.Any((KeyValuePair<GraphItem, int> requiredItem) => itemTypes.Contains(requiredItem.Key.ItemType)));
}
public void RemoveRecipesForTypes(List<string> itemTypes)
{
int count = Recipes.Count;
Dictionary<string, GraphRecipe> dictionary = Recipes.Where((KeyValuePair<string, GraphRecipe> recipe) => !itemTypes.Contains(recipe.Value.CraftedItem.Item1.ItemType) && !recipe.Value.RequiredItems.Any((KeyValuePair<GraphItem, int> item) => itemTypes.Contains(item.Key.ItemType))).ToDictionary((KeyValuePair<string, GraphRecipe> recipe) => recipe.Key, (KeyValuePair<string, GraphRecipe> recipe) => recipe.Value);
Recipes.Clear();
Extensions.AddRange<string, GraphRecipe>(Recipes, dictionary);
Logger.LogInfo("reduced '" + Name + "' recipes " + $"from original count {count} to reduced count {Recipes.Count}");
}
public override string ToString()
{
string text = string.Join("\n ", Recipes.Select((KeyValuePair<string, GraphRecipe> recipe) => recipe.Value.ToString().Replace("\n", "\n ")));
return "name '" + Name + "' has recipes:\n " + text;
}
}
public class GraphCraftingStation : BaseCrafting
{
public readonly List<string> ExtensionNames;
private GraphCraftingStation(string stationName, List<string> extensionNames)
: base(stationName)
{
ExtensionNames = extensionNames;
}
public static Dictionary<string, GraphCraftingStation> FromExtensionsAndStations(List<StationExtension> extensions, List<CraftingStation> stations)
{
Dictionary<string, GraphCraftingStation> stationsFromExtensions = (from extension in extensions
select Tuple.Create(((Object)(object)extension.m_craftingStation != (Object)null) ? ((Object)extension.m_craftingStation).name : "missing station", ((Object)extension).name) into tuple
group tuple by tuple.Item1).ToDictionary((IGrouping<string, Tuple<string, string>> group) => group.Key, (IGrouping<string, Tuple<string, string>> group) => new GraphCraftingStation(group.Key, group.Select((Tuple<string, string> tuple) => tuple.Item2).ToList()));
GraphCraftingStation value;
return stations.ToDictionary((CraftingStation station) => ((Object)station).name, (CraftingStation station) => stationsFromExtensions.TryGetValue(((Object)station).name, out value) ? value : new GraphCraftingStation(((Object)station).name, new List<string>()));
}
public override string ToString()
{
if (ExtensionNames.Count <= 0)
{
return "[crafting station " + base.ToString() + "\n]";
}
string text = string.Join(", ", ExtensionNames);
return "[crafting station " + base.ToString() + "\n has extensions: " + text + "\n]";
}
}
public class GraphItem
{
public string ItemName { get; private set; }
public string ItemType { get; set; }
private GraphItem()
{
}
public static GraphItem GetOrCreate(string itemName, string itemType)
{
if (DataHarvester.Items.TryGetValue(itemName, out var value))
{
return value;
}
GraphItem graphItem = new GraphItem
{
ItemName = itemName,
ItemType = itemType
};
DataHarvester.Items.Add(itemName, graphItem);
return graphItem;
}
public static GraphItem GetOrCreate(ItemDrop drop)
{
return GetOrCreate(((Object)drop).name, ((object)(ItemType)(ref drop.m_itemData.m_shared.m_itemType)).ToString());
}
[CanBeNull]
public static GraphItem GetOrCreate(GameObject gameObject)
{
ItemDrop val = default(ItemDrop);
if (!gameObject.TryGetComponent<ItemDrop>(ref val))
{
return null;
}
return GetOrCreate(((Object)val).name, ((object)(ItemType)(ref val.m_itemData.m_shared.m_itemType)).ToString());
}
public override string ToString()
{
return "[item name '" + ItemName + "', type '" + ItemType + "']";
}
}
public class GraphPiece
{
public string PieceName;
public string RequiredCraftingStation;
public Dictionary<GraphItem, int> BuildRequirements;
public static GraphPiece FromPiece(Piece fromGame)
{
return new GraphPiece
{
PieceName = ((Object)fromGame).name,
RequiredCraftingStation = (((Object)(object)fromGame.m_craftingStation == (Object)null) ? "no_station_required" : ((Object)fromGame.m_craftingStation).name),
BuildRequirements = fromGame.m_resources.Where((Requirement resource) => (Object)(object)resource.m_resItem != (Object)null).ToDictionary((Requirement resource) => GraphItem.GetOrCreate(((Object)resource.m_resItem).name, ((object)(ItemType)(ref resource.m_resItem.m_itemData.m_shared.m_itemType)).ToString()), (Requirement resource) => resource.m_amount)
};
}
public override string ToString()
{
if (BuildRequirements.Count <= 0)
{
return "[piece name '" + PieceName + "', requires station '" + RequiredCraftingStation + "']";
}
string text = string.Join("\n ", BuildRequirements.Select((KeyValuePair<GraphItem, int> requirement) => $"[{requirement.Key} x{requirement.Value}]"));
return "[piece name '" + PieceName + "', requires station '" + RequiredCraftingStation + "', requirements:\n " + text + "\n]";
}
}
public class GraphProcessor : BaseCrafting
{
private GraphProcessor(string name, Dictionary<string, GraphRecipe> recipes)
: base(name, recipes)
{
}
public static GraphProcessor FromSmelter(Smelter smelter)
{
return new GraphProcessor(((Object)smelter).name, GraphRecipe.FromSmelter(smelter));
}
public static GraphProcessor FromIncinerator(Incinerator incinerator)
{
return new GraphProcessor(((Object)incinerator).name, GraphRecipe.FromIncinerator(incinerator));
}
public static GraphProcessor FromFermenter(Fermenter fermenter)
{
return new GraphProcessor(((Object)fermenter).name, GraphRecipe.FromFermenter(fermenter));
}
public static GraphProcessor FromCookingStation(CookingStation cookingStation)
{
return new GraphProcessor(((Object)cookingStation).name, GraphRecipe.FromCookingStation(cookingStation));
}
public override string ToString()
{
return "[processor " + base.ToString() + "\n]";
}
}
public class GraphRecipe
{
public string RecipeName;
public Tuple<GraphItem, int> CraftedItem;
public Dictionary<GraphItem, int> RequiredItems;
private GraphRecipe()
{
}
public static GraphRecipe FromRecipe(Recipe fromGame)
{
if ((Object)(object)fromGame.m_item == (Object)null)
{
throw new ArgumentException("recipe '" + ((Object)fromGame).name + "' does not produce an item");
}
if (!fromGame.m_resources.ToList().TrueForAll((Requirement recourse) => (Object)(object)recourse.m_resItem != (Object)null))
{
throw new ArgumentException("recipe '" + ((Object)fromGame).name + "' contains a null required resource");
}
return new GraphRecipe
{
RecipeName = ((Object)fromGame).name,
CraftedItem = Tuple.Create(GraphItem.GetOrCreate(fromGame.m_item), 1),
RequiredItems = fromGame.m_resources.ToDictionary((Requirement requirement) => GraphItem.GetOrCreate(requirement.m_resItem), (Requirement requirement) => requirement.m_amount)
};
}
public static Dictionary<string, GraphRecipe> FromSmelter(Smelter smelter)
{
string fuel = (((Object)(object)smelter.m_fuelItem == (Object)null) ? "Air" : ((Object)smelter.m_fuelItem).name);
return (from recipe in smelter.m_conversion.Select(delegate(ItemConversion conversion)
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
GraphRecipe obj = new GraphRecipe
{
RecipeName = GetProcessorRecipeName(((Object)conversion.m_from).name, ((Object)conversion.m_to).name),
CraftedItem = Tuple.Create(GraphItem.GetOrCreate(conversion.m_to), 1)
};
Dictionary<GraphItem, int> dictionary = new Dictionary<GraphItem, int>();
string itemName = fuel;
ItemType val = (ItemType)1;
dictionary.Add(GraphItem.GetOrCreate(itemName, ((object)(ItemType)(ref val)).ToString()), smelter.m_fuelPerProduct);
dictionary.Add(GraphItem.GetOrCreate(conversion.m_from), 1);
obj.RequiredItems = dictionary;
return obj;
})
group recipe by recipe.RecipeName).ToDictionary((IGrouping<string, GraphRecipe> group) => group.Key, (IGrouping<string, GraphRecipe> group) => group.First());
}
public static Dictionary<string, GraphRecipe> FromIncinerator(Incinerator incinerator)
{
return (from conversion in incinerator.m_conversions
select new GraphRecipe
{
RecipeName = GetProcessorRecipeName("Incinerator_Sacrifice", ((Object)conversion.m_result).name),
CraftedItem = Tuple.Create(GraphItem.GetOrCreate(conversion.m_result), conversion.m_resultAmount),
RequiredItems = conversion.m_requirements.ToDictionary((Requirement requirement) => GraphItem.GetOrCreate(requirement.m_resItem), (Requirement requirement) => requirement.m_amount)
} into recipe
group recipe by recipe.RecipeName).ToDictionary((IGrouping<string, GraphRecipe> group) => group.Key, (IGrouping<string, GraphRecipe> group) => new GraphRecipe
{
RecipeName = group.Key,
CraftedItem = group.First().CraftedItem,
RequiredItems = group.SelectMany((GraphRecipe recipe) => recipe.RequiredItems).ToDictionary((KeyValuePair<GraphItem, int> tuple) => tuple.Key, (KeyValuePair<GraphItem, int> tuple) => tuple.Value)
});
}
public static Dictionary<string, GraphRecipe> FromFermenter(Fermenter fermenter)
{
return (from conversion in fermenter.m_conversion
select new GraphRecipe
{
RecipeName = GetProcessorRecipeName(((Object)conversion.m_from).name, ((Object)conversion.m_to).name),
CraftedItem = Tuple.Create(GraphItem.GetOrCreate(conversion.m_to), conversion.m_producedItems),
RequiredItems = new Dictionary<GraphItem, int> {
{
GraphItem.GetOrCreate(conversion.m_from),
1
} }
} into recipe
group recipe by recipe.RecipeName).ToDictionary((IGrouping<string, GraphRecipe> group) => group.Key, (IGrouping<string, GraphRecipe> group) => group.First());
}
public static Dictionary<string, GraphRecipe> FromCookingStation(CookingStation cookingStation)
{
string fuel = (((Object)(object)cookingStation.m_fuelItem == (Object)null) ? "Fire" : ((Object)cookingStation.m_fuelItem).name);
return (from recipe in cookingStation.m_conversion.Select(delegate(ItemConversion conversion)
{
//IL_005d: Unknown result type (might be due to invalid IL or missing references)
GraphRecipe obj = new GraphRecipe
{
RecipeName = GetProcessorRecipeName(((Object)conversion.m_from).name, ((Object)conversion.m_to).name),
CraftedItem = Tuple.Create(GraphItem.GetOrCreate(conversion.m_to), 1)
};
Dictionary<GraphItem, int> obj2 = new Dictionary<GraphItem, int> {
{
GraphItem.GetOrCreate(conversion.m_from),
1
} };
string itemName = fuel;
ItemType val = (ItemType)1;
obj2.Add(GraphItem.GetOrCreate(itemName, ((object)(ItemType)(ref val)).ToString()), 1);
obj.RequiredItems = obj2;
return obj;
})
group recipe by recipe.RecipeName).ToDictionary((IGrouping<string, GraphRecipe> group) => group.Key, (IGrouping<string, GraphRecipe> group) => group.First());
}
private static string GetProcessorRecipeName(string fromItem, string toItem)
{
return "[processing " + fromItem + " to " + toItem + "]";
}
public override string ToString()
{
string text = string.Join("\n ", RequiredItems.Select((KeyValuePair<GraphItem, int> requiredItem) => $"[{requiredItem.Key} x{requiredItem.Value}]"));
return $"[recipe '{RecipeName}' to create {CraftedItem.Item1} requires:\n" + " " + text + "\n]";
}
}
}
namespace PrefabDependencyTree.Data
{
public static class DataHarvester
{
public static readonly Dictionary<string, GraphItem> Items = new Dictionary<string, GraphItem>();
public static readonly Dictionary<string, GraphRecipe> UnboundRecipes = new Dictionary<string, GraphRecipe>();
public static readonly Dictionary<string, GraphCraftingStation> CraftingStations = new Dictionary<string, GraphCraftingStation>();
public static readonly Dictionary<string, GraphProcessor> Processors = new Dictionary<string, GraphProcessor>();
public static readonly Dictionary<Tuple<string, DropType>, List<GraphItem>> Drops = new Dictionary<Tuple<string, DropType>, List<GraphItem>>();
public static readonly Dictionary<string, GraphPiece> Pieces = new Dictionary<string, GraphPiece>();
public static void Initialize()
{
InitializeSmelters();
InitializeIncinerator();
InitializeCookingStations();
InitializeFermenters();
InitializeCraftingStations();
InitializePieces();
InitializeRecipes();
InitializeDrops();
LogOverview();
LogItemTypesOverview();
}
private static void LogOverview()
{
Logger.LogInfo("vvvv data harvester overview vvvv");
Logger.LogInfo($" total {Items.Count} items registered");
Logger.LogInfo($" total {Drops.Count} drops registered");
Logger.LogInfo($" total {Pieces.Count} pieces registered");
Logger.LogInfo($" total {CraftingStations.Count} crafting stations registered");
Logger.LogInfo($" total {Processors.Count} processor stations (fermenter, smelter, ...) registered");
Logger.LogInfo($" total {UnboundRecipes.Count} unbound recipes registered");
Logger.LogInfo("^^^^ data harvester overview ^^^^");
}
private static void LogItemTypesOverview()
{
Dictionary<string, int> source = (from item in Items
group item by item.Value.ItemType).ToDictionary((IGrouping<string, KeyValuePair<string, GraphItem>> group) => group.Key, (IGrouping<string, KeyValuePair<string, GraphItem>> group) => group.Count());
Logger.LogInfo("vvvv item types overview vvvv");
foreach (KeyValuePair<string, int> item in source.OrderBy((KeyValuePair<string, int> pair) => pair.Key))
{
Logger.LogInfo($"item type '{item.Key}' -> found {item.Value} items");
}
Logger.LogInfo("^^^^ item types overview ^^^^");
}
public static List<string> LogAllToString()
{
List<string> list = new List<string>();
list.Add("==== debug log output for all prefabs ====");
list.AddRange(Items.Select((KeyValuePair<string, GraphItem> item) => item.Value.ToString()));
list.AddRange(from <>h__TransparentIdentifier0 in Drops.Select(delegate(KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop)
{
KeyValuePair<Tuple<string, DropType>, List<GraphItem>> keyValuePair = drop;
return new
{
drop = drop,
dropsList = string.Join("\n ", keyValuePair.Value.Select((GraphItem item) => item.ToString()))
};
})
select $"['{<>h__TransparentIdentifier0.drop.Key}' drops:\n" + " " + <>h__TransparentIdentifier0.dropsList + "\n]");
list.AddRange(Pieces.Select((KeyValuePair<string, GraphPiece> piece) => piece.Value.ToString()));
list.AddRange(CraftingStations.Select((KeyValuePair<string, GraphCraftingStation> station) => station.Value.ToString()));
list.AddRange(Processors.Select((KeyValuePair<string, GraphProcessor> processor) => processor.Value.ToString()));
list.AddRange(UnboundRecipes.Select((KeyValuePair<string, GraphRecipe> recipe) => recipe.Value.ToString()));
list.Add("==== debug log output for all prefabs ====");
return list;
}
public static List<string> LogAllItemsToCategorizedYaml()
{
List<GraphItem> second = CraftingStations.SelectMany((KeyValuePair<string, GraphCraftingStation> cs) => cs.Value.Recipes.Select((KeyValuePair<string, GraphRecipe> recipe) => recipe.Value).ToList()).Union(UnboundRecipes.Select((KeyValuePair<string, GraphRecipe> unbound) => unbound.Value)).Union(Processors.SelectMany((KeyValuePair<string, GraphProcessor> processor) => processor.Value.Recipes.Select((KeyValuePair<string, GraphRecipe> recipe) => recipe.Value).ToList()))
.ToList()
.SelectMany(delegate(GraphRecipe recipe)
{
List<GraphItem> list2 = new List<GraphItem>();
list2.Add(recipe.CraftedItem.Item1);
list2.AddRange(recipe.RequiredItems.Select((KeyValuePair<GraphItem, int> req) => req.Key));
return list2;
})
.ToList();
Dictionary<string, List<string>> dictionary = (from item in Items.Select((KeyValuePair<string, GraphItem> item) => item.Value).Union(second).Union(Drops.SelectMany((KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop) => drop.Value))
.ToList()
group item by item.ItemType).ToDictionary((IGrouping<string, GraphItem> group) => group.Key, (IGrouping<string, GraphItem> group) => (from item in @group.Select((GraphItem item) => item.ItemName).Distinct()
orderby item
select item).ToList());
List<string> list = new List<string>();
foreach (KeyValuePair<string, List<string>> item in dictionary)
{
list.Add(item.Key + ":");
list.AddRange(item.Value.Select((string item) => " - " + item));
}
return list;
}
private static void InitializePieces()
{
Dictionary<string, GraphPiece> dictionary = Cache.GetPrefabs(typeof(Piece)).ToDictionary((KeyValuePair<string, Object> kv) => kv.Key, (KeyValuePair<string, Object> kv) => GraphPiece.FromPiece((Piece)kv.Value));
dictionary.Where((KeyValuePair<string, GraphPiece> kv) => !CraftingStations.ContainsKey(kv.Key) && !Processors.ContainsKey(kv.Key)).ToList().ForEach(delegate(KeyValuePair<string, GraphPiece> piece)
{
Pieces.Add(piece.Key, piece.Value);
});
Logger.LogInfo($"loaded {dictionary.Count} pieces from game");
}
private static void InitializeSmelters()
{
Dictionary<string, GraphProcessor> dictionary = Cache.GetPrefabs(typeof(Smelter)).ToDictionary((KeyValuePair<string, Object> kv) => kv.Key, (KeyValuePair<string, Object> kv) => GraphProcessor.FromSmelter((Smelter)kv.Value));
dictionary.ToList().ForEach(delegate(KeyValuePair<string, GraphProcessor> smelter)
{
Processors.Add(smelter.Key, smelter.Value);
});
int num = dictionary.Select((KeyValuePair<string, GraphProcessor> smelter) => smelter.Value.Recipes.Count).Sum();
Logger.LogInfo($"loaded {dictionary.Count} smelters with {num} conversions from game");
}
private static void InitializeIncinerator()
{
Dictionary<string, GraphProcessor> dictionary = Cache.GetPrefabs(typeof(Incinerator)).ToDictionary((KeyValuePair<string, Object> kv) => kv.Key, (KeyValuePair<string, Object> kv) => GraphProcessor.FromIncinerator((Incinerator)kv.Value));
dictionary.ToList().ForEach(delegate(KeyValuePair<string, GraphProcessor> incinerator)
{
Processors.Add(incinerator.Key, incinerator.Value);
});
int num = dictionary.Select((KeyValuePair<string, GraphProcessor> incinerator) => incinerator.Value.Recipes.Count).Sum();
Logger.LogInfo($"loaded {dictionary.Count} incinerators with {num} conversions from game");
}
private static void InitializeCookingStations()
{
Dictionary<string, GraphProcessor> dictionary = Cache.GetPrefabs(typeof(CookingStation)).ToDictionary((KeyValuePair<string, Object> kv) => kv.Key, (KeyValuePair<string, Object> kv) => GraphProcessor.FromCookingStation((CookingStation)kv.Value));
dictionary.ToList().ForEach(delegate(KeyValuePair<string, GraphProcessor> fermenter)
{
Processors.Add(fermenter.Key, fermenter.Value);
});
int num = dictionary.Select((KeyValuePair<string, GraphProcessor> smelter) => smelter.Value.Recipes.Count).Sum();
Logger.LogInfo($"loaded {dictionary.Count} cooking stations with {num} conversions from game");
}
private static void InitializeFermenters()
{
Dictionary<string, GraphProcessor> dictionary = Cache.GetPrefabs(typeof(Fermenter)).ToDictionary((KeyValuePair<string, Object> kv) => kv.Key, (KeyValuePair<string, Object> kv) => GraphProcessor.FromFermenter((Fermenter)kv.Value));
dictionary.ToList().ForEach(delegate(KeyValuePair<string, GraphProcessor> fermenter)
{
Processors.Add(fermenter.Key, fermenter.Value);
});
int num = dictionary.Select((KeyValuePair<string, GraphProcessor> smelter) => smelter.Value.Recipes.Count).Sum();
Logger.LogInfo($"loaded {dictionary.Count} fermenters with {num} conversions from game");
}
private static void InitializeCraftingStations()
{
Dictionary<string, GraphCraftingStation> dictionary = GraphCraftingStation.FromExtensionsAndStations(((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(StationExtension))).Select((Func<KeyValuePair<string, Object>, StationExtension>)((KeyValuePair<string, Object> kv) => (StationExtension)kv.Value)).ToList(), ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(CraftingStation))).Select((Func<KeyValuePair<string, Object>, CraftingStation>)((KeyValuePair<string, Object> kv) => (CraftingStation)kv.Value)).ToList());
dictionary.ToList().ForEach(delegate(KeyValuePair<string, GraphCraftingStation> station)
{
CraftingStations.Add(station.Key, station.Value);
});
Logger.LogInfo($"loaded {dictionary.Count} crafting stations from game");
}
private static void InitializeRecipes()
{
foreach (KeyValuePair<string, Recipe> item in ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(Recipe))).ToDictionary((Func<KeyValuePair<string, Object>, string>)((KeyValuePair<string, Object> kv) => kv.Key), (Func<KeyValuePair<string, Object>, Recipe>)((KeyValuePair<string, Object> kv) => (Recipe)kv.Value)))
{
if ((Object)(object)item.Value.m_item == (Object)null)
{
Logger.LogInfo("recipe '" + item.Key + "' does not create an item - skipping");
}
else if ((Object)(object)item.Value.m_craftingStation != (Object)null)
{
if (CraftingStations.TryGetValue(((Object)item.Value.m_craftingStation).name, out var value))
{
value.Recipes.Add(item.Key, GraphRecipe.FromRecipe(item.Value));
continue;
}
Logger.LogWarning("recipe '" + item.Key + "': station '" + ((Object)item.Value.m_craftingStation).name + "' not found");
}
else
{
UnboundRecipes.Add(item.Key, GraphRecipe.FromRecipe(item.Value));
}
}
int num = CraftingStations.Select((KeyValuePair<string, GraphCraftingStation> station) => station.Value.Recipes.Count).Sum();
Logger.LogInfo($"loaded {num} recipes bound to crafting stations from game");
Logger.LogInfo($"loaded {UnboundRecipes.Count} recipes from game that are not bound to a crafting station");
}
private static void InitializeDrops()
{
List<Initializer> list = new List<Initializer>();
list.Add(new ContainerDropsInitializer());
list.Add(new DestructibleDropsInitializer());
list.Add(new TreeLogDropsInitializer());
list.Add(new TreeBaseDropsInitializer());
list.Add(new CharacterDropInitializer());
list.Add(new MineRockDropsInitializer());
list.Add(new MineRock5DropInitializer());
list.Add(new LootSpawnerDropsInitializer());
list.Add(new PickableDropInitializer());
list.Add(new PickableExtraDropInitializer());
list.Add(new PickableItemDropInitializer());
list.Add(new PickableItemRandomDropInitializer());
list.ForEach(delegate(Initializer initializer)
{
try
{
initializer.InitializeDrops();
}
catch (Exception ex)
{
Logger.LogError("got exception on initializing: " + ex.Message);
Logger.LogError(ex.StackTrace);
}
});
}
}
public class GraphBuilder
{
private readonly DotGraph Graph = new DotGraph().WithIdentifier("graph").Directed();
private readonly Dictionary<string, DotNode> Nodes = new Dictionary<string, DotNode>();
private readonly Dictionary<string, DotEdge> Edges = new Dictionary<string, DotEdge>();
public void AddNode(GraphItem item)
{
AddNode(item.ItemName, item.ItemType);
}
public void AddNode(string name, string nodeType)
{
//IL_004b: Unknown result type (might be due to invalid IL or missing references)
if (string.IsNullOrEmpty(name))
{
Logger.LogWarning("tried adding empty node name");
}
else
{
if (Nodes.ContainsKey(name))
{
return;
}
DotNode dotNode = new DotNode().WithIdentifier(name).WithLabel(name).WithShape(DotNodeShape.Rectangle);
if (nodeType != null)
{
DropType result2;
if (Enum.TryParse<ItemType>(nodeType, out ItemType result))
{
SetNodeColorItemType(dotNode, result);
}
else if (Enum.TryParse<DropType>(nodeType, out result2))
{
SetNodeColorDropType(dotNode, result2);
}
else
{
if (!Enum.TryParse<NodeType>(nodeType, out var result3))
{
throw new ArgumentException("node type '" + nodeType + "' does not match any types known");
}
SetNodePieceTypeOption(dotNode, result3);
}
}
Nodes.Add(name, dotNode);
}
}
private static void SetNodeColorDropType(DotNode node, DropType dropType)
{
switch (dropType)
{
case DropType.Character:
node.WithColor(DotColor.Orange);
break;
case DropType.Container:
case DropType.LootSpawner:
node.WithColor(DotColor.Beige);
break;
case DropType.Destructible:
node.WithColor(DotColor.Crimson);
break;
case DropType.Pickable:
node.WithColor(DotColor.Ivory);
break;
case DropType.Tree:
node.WithColor(DotColor.Brown);
break;
case DropType.MineRock:
node.WithShape(DotNodeShape.Diamond);
node.WithColor(DotColor.SlateGrey);
break;
default:
Logger.LogWarning("node type '" + dropType.ToString() + "' not supported");
break;
}
}
private static void SetNodeColorItemType(DotNode node, ItemType itemType)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0066: Expected I4, but got Unknown
switch ((int)itemType)
{
case 9:
case 23:
node.WithColor(DotColor.Cyan);
break;
case 6:
case 7:
case 11:
case 12:
case 17:
node.WithColor(DotColor.DarkGrey);
node.WithFontColor(DotColor.White);
break;
case 15:
case 18:
case 19:
node.WithColor(DotColor.Indigo);
break;
case 3:
case 4:
case 5:
case 14:
case 20:
case 22:
node.WithColor(DotColor.IndianRed);
break;
case 2:
node.WithColor(DotColor.LightGreen);
break;
case 21:
node.WithColor(DotColor.LightBlue);
break;
case 1:
node.WithColor(DotColor.SandyBrown);
break;
case 10:
case 16:
node.WithColor(DotColor.Grey);
node.WithFontColor(DotColor.White);
break;
case 0:
node.WithColor(DotColor.Yellow);
break;
case 13:
node.WithColor(DotColor.Violet);
node.WithFontColor(DotColor.White);
break;
default:
throw new ArgumentException("type '" + ((object)(ItemType)(ref itemType)).ToString() + "' not supported");
}
}
private static void SetNodePieceTypeOption(DotNode node, NodeType nodeType)
{
switch (nodeType)
{
case NodeType.Piece:
node.WithShape(DotNodeShape.Assembly);
node.WithColor(DotColor.Brown);
break;
case NodeType.Processor:
node.WithShape(DotNodeShape.Circle);
node.WithColor(DotColor.Gold);
break;
case NodeType.CraftingStation:
node.WithShape(DotNodeShape.Circle);
node.WithColor(DotColor.Gold);
break;
case NodeType.Recipe:
node.WithShape(DotNodeShape.Note);
node.WithColor(DotColor.Cornsilk);
break;
default:
throw new ArgumentException("type '" + nodeType.ToString() + "' not supported");
}
}
public void AddEdge(string from, string to)
{
string key = from + "->" + to;
if (!Edges.ContainsKey(key))
{
Edges.Add(key, new DotEdge().From(from).To(to));
}
}
public DotGraph BuildGraph()
{
Nodes.ToList().ForEach(delegate(KeyValuePair<string, DotNode> node)
{
Graph.Add(node.Value);
});
Edges.ToList().ForEach(delegate(KeyValuePair<string, DotEdge> edge)
{
Graph.Add(edge.Value);
});
return Graph;
}
}
public enum NodeType
{
Piece,
CraftingStation,
Processor,
Recipe
}
public enum DropType
{
Character,
Container,
Destructible,
LootSpawner,
MineRock,
Pickable,
Tree
}
public enum FilterType
{
Include,
Exclude,
Unfiltered
}
}
namespace PrefabDependencyTree.Data.Filters
{
public class ExcludeFilterTypes : FilteredData
{
public ExcludeFilterTypes(List<string> itemTypeFilters)
{
ItemTypeFilters = itemTypeFilters;
FilterType = FilterType.Exclude;
Items = DataHarvester.Items.Where((KeyValuePair<string, GraphItem> item) => !itemTypeFilters.Contains(item.Value.ItemType)).ToDictionary((KeyValuePair<string, GraphItem> pair) => pair.Key, (KeyValuePair<string, GraphItem> pair) => pair.Value);
UnboundRecipes = DataHarvester.UnboundRecipes.Where((KeyValuePair<string, GraphRecipe> recipe) => !itemTypeFilters.Contains(recipe.Value.CraftedItem.Item1.ItemType) && !recipe.Value.RequiredItems.Any((KeyValuePair<GraphItem, int> requiredItem) => itemTypeFilters.Contains(requiredItem.Key.ItemType))).ToDictionary((KeyValuePair<string, GraphRecipe> pair) => pair.Key, (KeyValuePair<string, GraphRecipe> pair) => pair.Value);
CraftingStations = (from station in DataHarvester.CraftingStations.ToDictionary((KeyValuePair<string, GraphCraftingStation> station) => station.Key, delegate(KeyValuePair<string, GraphCraftingStation> station)
{
station.Value.RemoveRecipesForTypes(itemTypeFilters);
return station.Value;
})
where station.Value.Recipes.Count > 0
select station).ToDictionary((KeyValuePair<string, GraphCraftingStation> kv) => kv.Key, (KeyValuePair<string, GraphCraftingStation> kv) => kv.Value);
Processors = (from processor in DataHarvester.Processors.ToDictionary((KeyValuePair<string, GraphProcessor> processor) => processor.Key, delegate(KeyValuePair<string, GraphProcessor> processor)
{
processor.Value.RemoveRecipesForTypes(itemTypeFilters);
return processor.Value;
})
where processor.Value.Recipes.Count > 0
select processor).ToDictionary((KeyValuePair<string, GraphProcessor> kv) => kv.Key, (KeyValuePair<string, GraphProcessor> kv) => kv.Value);
Drops = (from drop in DataHarvester.Drops.ToDictionary((KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop) => drop.Key, delegate(KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop)
{
List<GraphItem> collection = drop.Value.Where((GraphItem item) => !itemTypeFilters.Contains(item.ItemType)).ToList();
drop.Value.Clear();
drop.Value.AddRange(collection);
return drop.Value;
})
where drop.Value.Count > 0
select drop).ToDictionary((KeyValuePair<Tuple<string, DropType>, List<GraphItem>> kv) => kv.Key, (KeyValuePair<Tuple<string, DropType>, List<GraphItem>> kv) => kv.Value);
Pieces = DataHarvester.Pieces.Where((KeyValuePair<string, GraphPiece> piece) => !piece.Value.BuildRequirements.Any((KeyValuePair<GraphItem, int> requirement) => itemTypeFilters.Contains(requirement.Key.ItemType))).ToDictionary((KeyValuePair<string, GraphPiece> pair) => pair.Key, (KeyValuePair<string, GraphPiece> pair) => pair.Value);
}
}
public abstract class FilteredData
{
protected Dictionary<string, GraphItem> Items;
protected Dictionary<string, GraphRecipe> UnboundRecipes;
protected Dictionary<string, GraphCraftingStation> CraftingStations;
protected Dictionary<string, GraphProcessor> Processors;
protected Dictionary<Tuple<string, DropType>, List<GraphItem>> Drops;
protected Dictionary<string, GraphPiece> Pieces;
protected List<string> ItemTypeFilters;
protected FilterType FilterType;
public void LogOverview()
{
Logger.LogInfo("vvvv filtered data overview vvvv");
Logger.LogInfo(" applied " + FilterType.ToString() + " filters: " + string.Join(", ", ItemTypeFilters));
Logger.LogInfo($" total {Items.Count} items registered");
Logger.LogInfo($" total {Drops.Count} drops registered");
Logger.LogInfo($" total {Pieces.Count} pieces registered");
Logger.LogInfo($" total {CraftingStations.Count} crafting stations registered");
Logger.LogInfo($" total {Processors.Count} processor stations (fermenter, smelter, ...) registered");
Logger.LogInfo($" total {UnboundRecipes.Count} unbound recipes registered");
Logger.LogInfo("^^^^ filtered data overview ^^^^");
}
public DotGraph CreateGraph()
{
GraphBuilder graphBuilder = new GraphBuilder();
Items.ToList().ForEach(delegate(KeyValuePair<string, GraphItem> item)
{
graphBuilder.AddNode(item.Value.ItemName, item.Value.ItemType);
});
foreach (KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop in Drops)
{
graphBuilder.AddNode(drop.Key.Item1, drop.Key.Item2.ToString());
foreach (GraphItem item in drop.Value)
{
graphBuilder.AddNode(item);
graphBuilder.AddEdge(drop.Key.Item1, item.ItemName);
}
}
AddRecipesToGraph(graphBuilder, UnboundRecipes);
foreach (KeyValuePair<string, GraphCraftingStation> craftingStation in CraftingStations)
{
graphBuilder.AddNode(craftingStation.Value.Name, NodeType.CraftingStation.ToString());
foreach (string extensionName in craftingStation.Value.ExtensionNames)
{
graphBuilder.AddNode(extensionName, NodeType.CraftingStation.ToString());
graphBuilder.AddEdge(extensionName, craftingStation.Value.Name);
}
AddRecipesToGraph(graphBuilder, craftingStation.Value.Recipes);
}
foreach (KeyValuePair<string, GraphProcessor> processor in Processors)
{
graphBuilder.AddNode(processor.Value.Name, NodeType.Processor.ToString());
AddRecipesToGraph(graphBuilder, processor.Value.Recipes);
}
foreach (KeyValuePair<string, GraphPiece> piece in Pieces)
{
graphBuilder.AddNode(piece.Value.PieceName, NodeType.Piece.ToString());
graphBuilder.AddNode(piece.Value.RequiredCraftingStation, NodeType.CraftingStation.ToString());
graphBuilder.AddEdge(piece.Value.RequiredCraftingStation, piece.Value.PieceName);
foreach (KeyValuePair<GraphItem, int> buildRequirement in piece.Value.BuildRequirements)
{
graphBuilder.AddNode(buildRequirement.Key);
graphBuilder.AddEdge(buildRequirement.Key.ItemName, piece.Value.PieceName);
}
}
return graphBuilder.BuildGraph();
}
private static void AddRecipesToGraph(GraphBuilder graphBuilder, Dictionary<string, GraphRecipe> recipes)
{
foreach (KeyValuePair<string, GraphRecipe> recipe in recipes)
{
graphBuilder.AddNode(recipe.Value.RecipeName, NodeType.Recipe.ToString());
graphBuilder.AddNode(recipe.Value.CraftedItem.Item1);
graphBuilder.AddEdge(recipe.Value.RecipeName, recipe.Value.CraftedItem.Item1.ItemName);
foreach (KeyValuePair<GraphItem, int> requiredItem in recipe.Value.RequiredItems)
{
graphBuilder.AddNode(requiredItem.Key);
graphBuilder.AddEdge(requiredItem.Key.ItemName, recipe.Value.RecipeName);
}
}
}
}
public class IncludeFilterTypes : FilteredData
{
public IncludeFilterTypes(List<string> itemTypeFilters)
{
ItemTypeFilters = itemTypeFilters;
FilterType = FilterType.Include;
Items = DataHarvester.Items.Where((KeyValuePair<string, GraphItem> item) => itemTypeFilters.Contains(item.Value.ItemType)).ToDictionary((KeyValuePair<string, GraphItem> pair) => pair.Key, (KeyValuePair<string, GraphItem> pair) => pair.Value);
UnboundRecipes = DataHarvester.UnboundRecipes.Where((KeyValuePair<string, GraphRecipe> recipe) => itemTypeFilters.Contains(recipe.Value.CraftedItem.Item1.ItemType) || recipe.Value.RequiredItems.Any((KeyValuePair<GraphItem, int> requiredItem) => itemTypeFilters.Contains(requiredItem.Key.ItemType))).ToDictionary((KeyValuePair<string, GraphRecipe> pair) => pair.Key, (KeyValuePair<string, GraphRecipe> pair) => pair.Value);
CraftingStations = DataHarvester.CraftingStations.Where((KeyValuePair<string, GraphCraftingStation> station) => station.Value.ContainsItemTypes(itemTypeFilters)).ToDictionary((KeyValuePair<string, GraphCraftingStation> pair) => pair.Key, (KeyValuePair<string, GraphCraftingStation> pair) => pair.Value);
Processors = DataHarvester.Processors.Where((KeyValuePair<string, GraphProcessor> processor) => processor.Value.ContainsItemTypes(itemTypeFilters)).ToDictionary((KeyValuePair<string, GraphProcessor> pair) => pair.Key, (KeyValuePair<string, GraphProcessor> pair) => pair.Value);
Drops = DataHarvester.Drops.Where((KeyValuePair<Tuple<string, DropType>, List<GraphItem>> drop) => drop.Value.Any((GraphItem item) => itemTypeFilters.Contains(item.ItemType))).ToDictionary((KeyValuePair<Tuple<string, DropType>, List<GraphItem>> pair) => pair.Key, (KeyValuePair<Tuple<string, DropType>, List<GraphItem>> pair) => pair.Value);
Pieces = DataHarvester.Pieces.Where((KeyValuePair<string, GraphPiece> piece) => piece.Value.BuildRequirements.Any((KeyValuePair<GraphItem, int> requirement) => itemTypeFilters.Contains(requirement.Key.ItemType))).ToDictionary((KeyValuePair<string, GraphPiece> pair) => pair.Key, (KeyValuePair<string, GraphPiece> pair) => pair.Value);
}
}
public class UnfilteredData : FilteredData
{
public UnfilteredData()
{
FilterType = FilterType.Unfiltered;
ItemTypeFilters = new List<string>();
Items = DataHarvester.Items;
UnboundRecipes = DataHarvester.UnboundRecipes;
CraftingStations = DataHarvester.CraftingStations;
Processors = DataHarvester.Processors;
Drops = DataHarvester.Drops;
Pieces = DataHarvester.Pieces;
}
}
}
namespace PrefabDependencyTree.Data.Drops
{
public class CharacterDropInitializer : DropsInitializer<CharacterDrop, Drop>
{
protected override Dictionary<Tuple<string, DropType>, CharacterDrop> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(Character))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Character)), (Func<KeyValuePair<string, Object>, CharacterDrop>)((KeyValuePair<string, Object> kv) => (CharacterDrop)((Component)(Character)kv.Value).GetComponent(typeof(CharacterDrop))));
}
protected override List<Drop> GetDropList(CharacterDrop input)
{
if ((Object)(object)input != (Object)null && input.m_drops != null)
{
return input.m_drops.ToList();
}
return new List<Drop>();
}
protected override GameObject GetObject(Drop input)
{
return input.m_prefab;
}
}
public class ContainerDropsInitializer : DropsInitializerDropData<Container>
{
protected override Dictionary<Tuple<string, DropType>, Container> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(Container))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Container)), (Func<KeyValuePair<string, Object>, Container>)((KeyValuePair<string, Object> kv) => (Container)kv.Value));
}
protected override List<DropData> GetDropList(Container input)
{
if (input.m_defaultItems != null)
{
return FromTable(input.m_defaultItems);
}
Logger.LogWarning($"'m_defaultItems' not found for {typeof(Container)}");
return new List<DropData>();
}
}
public class DestructibleDropsInitializer : DropsInitializerDropData<DropOnDestroyed>
{
protected override Dictionary<Tuple<string, DropType>, DropOnDestroyed> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(DropOnDestroyed))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Destructible)), (Func<KeyValuePair<string, Object>, DropOnDestroyed>)((KeyValuePair<string, Object> kv) => (DropOnDestroyed)kv.Value));
}
protected override List<DropData> GetDropList(DropOnDestroyed input)
{
if (input.m_dropWhenDestroyed != null)
{
return FromTable(input.m_dropWhenDestroyed);
}
Logger.LogWarning($"'m_dropWhenDestroyed' not found for {typeof(DropOnDestroyed)}");
return new List<DropData>();
}
}
public class LootSpawnerDropsInitializer : DropsInitializerDropData<LootSpawner>
{
protected override Dictionary<Tuple<string, DropType>, LootSpawner> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(LootSpawner))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.LootSpawner)), (Func<KeyValuePair<string, Object>, LootSpawner>)((KeyValuePair<string, Object> kv) => (LootSpawner)kv.Value));
}
protected override List<DropData> GetDropList(LootSpawner input)
{
if (input.m_items != null)
{
return FromTable(input.m_items);
}
Logger.LogWarning($"'m_items' not found for {typeof(LootSpawner)}");
return new List<DropData>();
}
}
public class MineRock5DropInitializer : DropsInitializerDropData<MineRock5>
{
protected override Dictionary<Tuple<string, DropType>, MineRock5> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(MineRock5))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.MineRock)), (Func<KeyValuePair<string, Object>, MineRock5>)((KeyValuePair<string, Object> kv) => (MineRock5)kv.Value));
}
protected override List<DropData> GetDropList(MineRock5 input)
{
if (input.m_dropItems != null)
{
return FromTable(input.m_dropItems);
}
Logger.LogWarning($"'m_dropItems' not found for {typeof(MineRock5)}");
return new List<DropData>();
}
}
public class MineRockDropsInitializer : DropsInitializerDropData<MineRock>
{
protected override Dictionary<Tuple<string, DropType>, MineRock> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(MineRock))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.MineRock)), (Func<KeyValuePair<string, Object>, MineRock>)((KeyValuePair<string, Object> kv) => (MineRock)kv.Value));
}
protected override List<DropData> GetDropList(MineRock input)
{
if (input.m_dropItems != null)
{
return FromTable(input.m_dropItems);
}
Logger.LogWarning($"'m_dropItems' not found for {typeof(MineRock)}");
return new List<DropData>();
}
}
public class PickableDropInitializer : DropsInitializer<Pickable, GameObject>
{
protected override Dictionary<Tuple<string, DropType>, Pickable> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(Pickable))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Pickable)), (Func<KeyValuePair<string, Object>, Pickable>)((KeyValuePair<string, Object> kv) => (Pickable)kv.Value));
}
protected override List<GameObject> GetDropList(Pickable input)
{
return new List<GameObject> { input.m_itemPrefab };
}
protected override GameObject GetObject(GameObject input)
{
return input;
}
}
public class PickableExtraDropInitializer : DropsInitializerDropData<Pickable>
{
protected override Dictionary<Tuple<string, DropType>, Pickable> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(Pickable))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Pickable)), (Func<KeyValuePair<string, Object>, Pickable>)((KeyValuePair<string, Object> kv) => (Pickable)kv.Value));
}
protected override List<DropData> GetDropList(Pickable input)
{
if (input.m_extraDrops != null)
{
return FromTable(input.m_extraDrops);
}
Logger.LogWarning($"'m_extraDrops' not found for {typeof(Pickable)}");
return new List<DropData>();
}
}
public class PickableItemDropInitializer : DropsInitializer<PickableItem, ItemDrop>
{
protected override Dictionary<Tuple<string, DropType>, PickableItem> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(PickableItem))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Pickable)), (Func<KeyValuePair<string, Object>, PickableItem>)((KeyValuePair<string, Object> kv) => (PickableItem)kv.Value));
}
protected override List<ItemDrop> GetDropList(PickableItem input)
{
return new List<ItemDrop> { input.m_itemPrefab };
}
protected override GameObject GetObject(ItemDrop input)
{
return ((Component)input).gameObject;
}
}
public class PickableItemRandomDropInitializer : DropsInitializer<PickableItem, RandomItem>
{
protected override Dictionary<Tuple<string, DropType>, PickableItem> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(PickableItem))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Pickable)), (Func<KeyValuePair<string, Object>, PickableItem>)((KeyValuePair<string, Object> kv) => (PickableItem)kv.Value));
}
protected override List<RandomItem> GetDropList(PickableItem input)
{
if (input.m_randomItemPrefabs != null)
{
return input.m_randomItemPrefabs.ToList();
}
Logger.LogWarning($"'m_randomItemPrefabs' not found for {typeof(PickableItem)}");
return new List<RandomItem>();
}
protected override GameObject GetObject(RandomItem input)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return ((Component)input.m_itemPrefab).gameObject;
}
}
public class TreeBaseDropsInitializer : DropsInitializerDropData<TreeBase>
{
protected override Dictionary<Tuple<string, DropType>, TreeBase> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(TreeBase))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Tree)), (Func<KeyValuePair<string, Object>, TreeBase>)((KeyValuePair<string, Object> kv) => (TreeBase)kv.Value));
}
protected override List<DropData> GetDropList(TreeBase input)
{
if (input.m_dropWhenDestroyed != null)
{
return FromTable(input.m_dropWhenDestroyed);
}
Logger.LogWarning($"'m_dropWhenDestroyed' not found for {typeof(TreeBase)}");
return new List<DropData>();
}
}
public class TreeLogDropsInitializer : DropsInitializerDropData<TreeLog>
{
protected override Dictionary<Tuple<string, DropType>, TreeLog> GetGameObjects()
{
return ((IEnumerable<KeyValuePair<string, Object>>)Cache.GetPrefabs(typeof(TreeLog))).ToDictionary((Func<KeyValuePair<string, Object>, Tuple<string, DropType>>)((KeyValuePair<string, Object> kv) => Tuple.Create(kv.Key, DropType.Tree)), (Func<KeyValuePair<string, Object>, TreeLog>)((KeyValuePair<string, Object> kv) => (TreeLog)kv.Value));
}
protected override List<DropData> GetDropList(TreeLog input)
{
if (input.m_dropWhenDestroyed != null)
{
return FromTable(input.m_dropWhenDestroyed);
}
Logger.LogWarning($"'m_dropWhenDestroyed' not found for {typeof(TreeLog)}");
return new List<DropData>();
}
}
}
namespace PrefabDependencyTree.Data.Drops.Generic
{
public abstract class DropsInitializer<T, U> : Initializer
{
protected abstract Dictionary<Tuple<string, DropType>, T> GetGameObjects();
protected abstract List<U> GetDropList(T input);
protected abstract GameObject GetObject(U input);
public void InitializeDrops()
{
int count = DataHarvester.Drops.Count;
foreach (KeyValuePair<Tuple<string, DropType>, T> gameObject in GetGameObjects())
{
List<U> list = (from drop in GetDropList(gameObject.Value)
where drop != null
select drop).ToList();
if (list.Count <= 0)
{
Logger.LogInfo($"{typeof(T)} '{gameObject.Key}' does not have drop data - skipping");
continue;
}
List<GraphItem> value;
List<GraphItem> list2 = (DataHarvester.Drops.TryGetValue(gameObject.Key, out value) ? value : new List<GraphItem>());
foreach (U item in list)
{
if (item == null)
{
Logger.LogInfo($"{typeof(T)} - {typeof(U)}: found null drop in drop data (length {list.Count})");
continue;
}
object obj = item;
ItemDrop val = (ItemDrop)((obj is ItemDrop) ? obj : null);
if (val != null)
{
list2.Add(GraphItem.GetOrCreate(val));
continue;
}
GraphItem orCreate = GraphItem.GetOrCreate(GetObject(item));
if (orCreate != null)
{
list2.Add(orCreate);
}
}
DataHarvester.Drops[Tuple.Create(gameObject.Key.Item1, gameObject.Key.Item2)] = list2.Distinct().ToList();
}
Logger.LogInfo($"loaded {DataHarvester.Drops.Count - count} drops from {typeof(T)} ({typeof(U)}) from game");
}
}
public abstract class DropsInitializerDropData<T> : DropsInitializer<T, DropData>
{
protected override GameObject GetObject(DropData input)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
return input.m_item;
}
protected List<DropData> FromTable(DropTable table)
{
if (table != null)
{
return table.m_drops;
}
Logger.LogWarning($"missing drop table for type '{typeof(T)}'");
return new List<DropData>();
}
}
public interface Initializer
{
void InitializeDrops();
}
}
namespace DotNetGraph.Extensions
{
internal static class DotBaseGraphExtensions
{
public static T WithIdentifier<T>(this T graph, string identifier, bool isHtml = false) where T : DotBaseGraph
{
graph.Identifier = new DotIdentifier(identifier, isHtml);
return graph;
}
public static T WithRankDir<T>(this T graph, DotRankDir rankDir) where T : DotBaseGraph
{
graph.RankDir = new DotRankDirAttribute(rankDir);
return graph;
}
public static T Add<T>(this T graph, IDotElement element) where T : DotBaseGraph
{
graph.Elements.Add(element);
return graph;
}
}
internal static class DotEdgeExtensions
{
public static DotEdge From(this DotEdge edge, string from, bool isHtml = false)
{
edge.From = new DotIdentifier(from, isHtml);
return edge;
}
public static DotEdge From(this DotEdge edge, DotNode from)
{
edge.From = from.Identifier;
return edge;
}
public static DotEdge To(this DotEdge edge, string to, bool isHtml = false)
{
edge.To = new DotIdentifier(to, isHtml);
return edge;
}
public static DotEdge To(this DotEdge edge, DotNode to)
{
edge.To = to.Identifier;
return edge;
}
public static DotEdge WithColor(this DotEdge edge, string color)
{
edge.Color = new DotColorAttribute(color);
return edge;
}
public static DotEdge WithColor(this DotEdge edge, DotColor color)
{
edge.Color = new DotColorAttribute(color);
return edge;
}
public static DotEdge WithStyle(this DotEdge edge, string style)
{
edge.Style = new DotEdgeStyleAttribute(style);
return edge;
}
public static DotEdge WithStyle(this DotEdge edge, DotEdgeStyle style)
{
edge.Style = new DotEdgeStyleAttribute(style);
return edge;
}
public static DotEdge WithPenWidth(this DotEdge edge, double width)
{
edge.PenWidth = new DotDoubleAttribute(width);
return edge;
}
public static DotEdge WithArrowHead(this DotEdge edge, string arrowType)
{
edge.ArrowHead = new DotEdgeArrowTypeAttribute(arrowType);
return edge;
}
public static DotEdge WithArrowHead(this DotEdge edge, DotEdgeArrowType arrowType)
{
edge.ArrowHead = new DotEdgeArrowTypeAttribute(arrowType);
return edge;
}
public static DotEdge WithArrowTail(this DotEdge edge, string arrowType)
{
edge.ArrowTail = new DotEdgeArrowTypeAttribute(arrowType);
return edge;
}
public static DotEdge WithArrowTail(this DotEdge edge, DotEdgeArrowType arrowType)
{
edge.ArrowTail = new DotEdgeArrowTypeAttribute(arrowType);
return edge;
}
public static DotEdge WithPos(this DotEdge edge, string value)
{
edge.Pos = new DotPointAttribute(value);
return edge;
}
public static DotEdge WithPos(this DotEdge edge, int x, int y, bool @fixed = false)
{
edge.Pos = new DotPointAttribute(new DotPoint(x, y, @fixed));
return edge;
}
public static DotEdge WithPos(this DotEdge edge, int x, int y, int z, bool @fixed = false)
{
edge.Pos = new DotPointAttribute(new DotPoint(x, y, z, @fixed));
return edge;
}
}
internal static class DotElementExtensions
{
public static T WithAttribute<T>(this T element, string name, IDotAttribute attribute) where T : DotElement
{
element.SetAttribute(name, attribute);
return element;
}
public static T WithAttribute<T>(this T element, string name, string value) where T : DotElement
{
element.SetAttribute(name, new DotAttribute(value));
return element;
}
public static T WithLabel<T>(this T element, string label, bool isHtml = false) where T : DotElement
{
element.Label = new DotLabelAttribute(label, isHtml);
return element;
}
public static T WithFontColor<T>(this T element, string color) where T : DotElement
{
element.FontColor = new DotColorAttribute(color);
return element;
}
public static T WithFontColor<T>(this T element, DotColor color) where T : DotElement
{
element.FontColor = new DotColorAttribute(color);
return element;
}
}
internal static class DotGraphExtensions
{
public static DotGraph Directed(this DotGraph graph, bool directed = true)
{
graph.Directed = directed;
return graph;
}
public static DotGraph Strict(this DotGraph graph, bool strict = true)
{
graph.Strict = strict;
return graph;
}
}
internal static class DotNodeExtensions
{
public static DotNode WithIdentifier(this DotNode node, string identifier, bool isHtml = false)
{
node.Identifier = new DotIdentifier(identifier, isHtml);
return node;
}
public static DotNode WithColor(this DotNode node, string color)
{
node.Color = new DotColorAttribute(color);
return node;
}
public static DotNode WithColor(this DotNode node, DotColor color)
{
node.Color = new DotColorAttribute(color);
return node;
}
public static DotNode WithFillColor(this DotNode node, string color)
{
node.FillColor = new DotColorAttribute(color);
return node;
}
public static DotNode WithFillColor(this DotNode node, DotColor color)
{
node.FillColor = new DotColorAttribute(color);
return node;
}
public static DotNode WithShape(this DotNode node, string shape)
{
node.Shape = new DotNodeShapeAttribute(shape);
return node;
}
public static DotNode WithShape(this DotNode node, DotNodeShape shape)
{
node.Shape = new DotNodeShapeAttribute(shape);
return node;
}
public static DotNode WithStyle(this DotNode node, string style)
{
node.Style = new DotNodeStyleAttribute(style);
return node;
}
public static DotNode WithStyle(this DotNode node, DotNodeStyle style)
{
node.Style = new DotNodeStyleAttribute(style);
return node;
}
public static DotNode WithWidth(this DotNode node, double width)
{
node.Width = new DotDoubleAttribute(width);
return node;
}
public static DotNode WithHeight(this DotNode node, double height)
{
node.Height = new DotDoubleAttribute(height);
return node;
}
public static DotNode WithPenWidth(this DotNode node, double width)
{
node.PenWidth = new DotDoubleAttribute(width);
return node;
}
public static DotNode WithPos(this DotNode node, string value)
{
node.Pos = new DotPointAttribute(value);
return node;
}
public static DotNode WithPos(this DotNode node, int x, int y, bool @fixed = false)
{
node.Pos = new DotPointAttribute(new DotPoint(x, y, @fixed));
return node;
}
public static DotNode WithPos(this DotNode node, int x, int y, int z, bool @fixed = false)
{
node.Pos = new DotPointAttribute(new DotPoint(x, y, z, @fixed));
return node;
}
}
internal static class DotSubgraphExtensions
{
public static DotSubgraph WithColor(this DotSubgraph subgraph, string color)
{
subgraph.Color = new DotColorAttribute(color);
return subgraph;
}
public static DotSubgraph WithColor(this DotSubgraph subgraph, DotColor color)
{
subgraph.Color = new DotColorAttribute(color);
return subgraph;
}
public static DotSubgraph WithStyle(this DotSubgraph subgraph, string style)
{
subgraph.Style = new DotSubgraphStyleAttribute(style);
return subgraph;
}
public static DotSubgraph WithStyle(this DotSubgraph subgraph, DotSubgraphStyle style)
{
subgraph.Style = new DotSubgraphStyleAttribute(style);
return subgraph;
}
}
internal static class EnumExtensions
{
public static string FlagsToString<T>(this T enumValue) where T : Enum
{
if (typeof(T).GetCustomAttribute<FlagsAttribute>() == null)
{
throw new InvalidOperationException($"The type '{typeof(T)}' doesn't have the [Flags] attribute specified.");
}
return string.Join(",", from T a in Enum.GetValues(typeof(T))
where enumValue.HasFlag(a)
select a.ToString().ToLowerInvariant());
}
}
internal static class StringExtensions
{
internal static string FormatGraphvizEscapedCharacters(this string value)
{
return value?.Replace("\\", "\\\\").Replace("\"", "\\\"").Replace("\r\n", "\\n")
.Replace("\n", "\\n");
}
}
}
namespace DotNetGraph.Core
{
internal abstract class DotBaseGraph : DotElement
{
public DotIdentifier Identifier { get; set; }
public DotRankDirAttribute RankDir
{
get
{
return GetAttributeOrDefault<DotRankDirAttribute>("rankdir");
}
set
{
SetAttribute("rankdir", value);
}
}
public List<IDotElement> Elements { get; } = new List<IDotElement>();
public DotNode GetNodeByIdentifier(string identifier, bool isHtml = false)
{
return Elements.Where((IDotElement e) => e is DotNode).Cast<DotNode>().FirstOrDefault((DotNode node) => node.Identifier == new DotIdentifier(identifier, isHtml));
}
public abstract override Task CompileAsync(CompilationContext context);
protected async Task CompileBodyAsync(CompilationContext context)
{
await Identifier.CompileAsync(context);
await context.WriteLineAsync(" {");
context.IndentationLevel++;
await CompileAttributesAsync(context);
foreach (IDotElement element in Elements)
{
await element.CompileAsync(context);
}
context.IndentationLevel--;
await context.WriteIndentationAsync();
await context.WriteLineAsync("}");
}
}
internal struct DotColor : IEquatable<DotColor>
{
public byte R;
public byte G;
public byte B;
public byte A;
public static DotColor AliceBlue { get; } = new DotColor(240, 248, byte.MaxValue);
public static DotColor AntiqueWhite { get; } = new DotColor(250, 235, 215);
public static DotColor Aqua { get; } = new DotColor(0, byte.MaxValue, byte.MaxValue);
public static DotColor Aquamarine { get; } = new DotColor(127, byte.MaxValue, 212);
public static DotColor Azure { get; } = new DotColor(240, byte.MaxValue, byte.MaxValue);
public static DotColor Beige { get; } = new DotColor(245, 245, 220);
public static DotColor Bisque { get; } = new DotColor(byte.MaxValue, 228, 196);
public static DotColor Black { get; } = new DotColor(0, 0, 0);
public static DotColor BlanchedAlmond { get; } = new DotColor(byte.MaxValue, 235, 205);
public static DotColor Blue { get; } = new DotColor(0, 0, byte.MaxValue);
public static DotColor BlueViolet { get; } = new DotColor(138, 43, 226);
public static DotColor Brown { get; } = new DotColor(165, 42, 42);
public static DotColor Burlywood { get; } = new DotColor(222, 184, 135);
public static DotColor CadetBlue { get; } = new DotColor(95, 158, 160);
public static DotColor Chartreuse { get; } = new DotColor(127, byte.MaxValue, 0);
public static DotColor Chocolate { get; } = new DotColor(210, 105, 30);
public static DotColor Coral { get; } = new DotColor(byte.MaxValue, 127, 80);
public static DotColor CornflowerBlue { get; } = new DotColor(100, 149, 237);
public static DotColor Cornsilk { get; } = new DotColor(byte.MaxValue, 248, 220);
public static DotColor Crimson { get; } = new DotColor(220, 20, 60);
public static DotColor Cyan { get; } = new DotColor(0, byte.MaxValue, byte.MaxValue);
public static DotColor DarkBlue { get; } = new DotColor(0, 0, 139);
public static DotColor DarkCyan { get; } = new DotColor(0, 139, 139);
public static DotColor DarkGoldenrod { get; } = new DotColor(184, 134, 11);
public static DotColor DarkGray { get; } = new DotColor(169, 169, 169);
public static DotColor DarkGreen { get; } = new DotColor(0, 100, 0);
public static DotColor DarkGrey { get; } = new DotColor(169, 169, 169);
public static DotColor DarkKhaki { get; } = new DotColor(189, 183, 107);
public static DotColor DarkMagenta { get; } = new DotColor(139, 0, 139);
public static DotColor DarkOliveGreen { get; } = new DotColor(85, 107, 47);
public static DotColor Darkorange { get; } = new DotColor(byte.MaxValue, 140, 0);
public static DotColor DarkOrchid { get; } = new DotColor(153, 50, 204);
public static DotColor DarkRed { get; } = new DotColor(139, 0, 0);
public static DotColor DarkSalmon { get; } = new DotColor(233, 150, 122);
public static DotColor DarkSeaGreen { get; } = new DotColor(143, 188, 143);
public static DotColor DarkSlateBlue { get; } = new DotColor(72, 61, 139);
public static DotColor DarkSlateGray { get; } = new DotColor(47, 79, 79);
public static DotColor DarkSlateGrey { get; } = new DotColor(47, 79, 79);
public static DotColor DarkTurquoise { get; } = new DotColor(0, 206, 209);
public static DotColor DarkViolet { get; } = new DotColor(148, 0, 211);
public static DotColor DeepPink { get; } = new DotColor(byte.MaxValue, 20, 147);
public static DotColor DeepSkyBlue { get; } = new DotColor(0, 191, byte.MaxValue);
public static DotColor DimGray { get; } = new DotColor(105, 105, 105);
public static DotColor DimGrey { get; } = new DotColor(105, 105, 105);
public static DotColor DodgerBlue { get; } = new DotColor(30, 144, byte.MaxValue);
public static DotColor Firebrick { get; } = new DotColor(178, 34, 34);
public static DotColor FloralWhite { get; } = new DotColor(byte.MaxValue, 250, 240);
public static DotColor ForestGreen { get; } = new DotColor(34, 139, 34);
public static DotColor Fuchsia { get; } = new DotColor(byte.MaxValue, 0, byte.MaxValue);
public static DotColor Gainsboro { get; } = new DotColor(220, 220, 220);
public static DotColor GhostWhite { get; } = new DotColor(248, 248, byte.MaxValue);
public static DotColor Gold { get; } = new DotColor(byte.MaxValue, 215, 0);
public static DotColor Goldenrod { get; } = new DotColor(218, 165, 32);
public static DotColor Gray { get; } = new DotColor(128, 128, 128);
public static DotColor Green { get; } = new DotColor(0, 128, 0);
public static DotColor GreenYellow { get; } = new DotColor(173, byte.MaxValue, 47);
public static DotColor Grey { get; } = new DotColor(128, 128, 128);
public static DotColor Honeydew { get; } = new DotColor(240, byte.MaxValue, 240);
public static DotColor HotPink { get; } = new DotColor(byte.MaxValue, 105, 180);
public static DotColor IndianRed { get; } = new DotColor(205, 92, 92);
public static DotColor Indigo { get; } = new DotColor(75, 0, 130);
public static DotColor Ivory { get; } = new DotColor(byte.MaxValue, byte.MaxValue, 240);
public static DotColor Khaki { get; } = new DotColor(240, 230, 140);
public static DotColor Lavender { get; } = new DotColor(230, 230, 250);
public static DotColor LavenderBlush { get; } = new DotColor(byte.MaxValue, 240, 245);
public static DotColor LawnGreen { get; } = new DotColor(124, 252, 0);
public static DotColor LemonChiffon { get; } = new DotColor(byte.MaxValue, 250, 205);
public static DotColor LightBlue { get; } = new DotColor(173, 216, 230);
public static DotColor LightCoral { get; } = new DotColor(240, 128, 128);
public static DotColor LightCyan { get; } = new DotColor(224, byte.MaxValue, byte.MaxValue);
public static DotColor LightGoldenrodYellow { get; } = new DotColor(250, 250, 210);
public static DotColor LightGray { get; } = new DotColor(211, 211, 211);
public static DotColor LightGrey { get; } = new DotColor(211, 211, 211);
public static DotColor LightGreen { get; } = new DotColor(144, 238, 144);
public static DotColor LightPink { get; } = new DotColor(byte.MaxValue, 182, 193);
public static DotColor LightSalmon { get; } = new DotColor(byte.MaxValue, 160, 122);
public static DotColor LightSeaGreen { get; } = new DotColor(32, 178, 170);
public static DotColor LightSkyBlue { get; } = new DotColor(135, 206, 250);
public static DotColor LightSlateGray { get; } = new DotColor(119, 136, 153);
public static DotColor LightSlateGrey { get; } = new DotColor(119, 136, 153);
public static DotColor LightSteelBlue { get; } = new DotColor(176, 196, 222);
public static DotColor LightYellow { get; } = new DotColor(byte.MaxValue, byte.MaxValue, 224);
public static DotColor Lime { get; } = new DotColor(0, byte.MaxValue, 0);
public static DotColor LimeGreen { get; } = new DotColor(50, 205, 50);
public static DotColor Linen { get; } = new DotColor(250, 240, 230);
public static DotColor Magenta { get; } = new DotColor(byte.MaxValue, 0, byte.MaxValue);
public static DotColor Maroon { get; } = new DotColor(128, 0, 0);
public static DotColor MediumAquamarine { get; } = new DotColor(102, 205, 170);
public static DotColor MediumBlue { get; } = new DotColor(0, 0, 205);
public static DotColor MediumOrchid { get; } = new DotColor(186, 85, 211);
public static DotColor MediumPurple { get; } = new DotColor(147, 112, 219);
public static DotColor MediumSeaGreen { get; } = new DotColor(60, 179, 113);
public static DotColor MediumSlateBlue { get; } = new DotColor(123, 104, 238);
public static DotColor MediumSpringGreen { get; } = new DotColor(0, 250, 154);
public static DotColor MediumTurquoise { get; } = new DotColor(72, 209, 204);
public static DotColor MediumVioletRed { get; } = new DotColor(199, 21, 133);
public static DotColor MidnightBlue { get; } = new DotColor(25, 25, 112);
public static DotColor MintCream { get; } = new DotColor(245, byte.MaxValue, 250);
public static DotColor MistyRose { get; } = new DotColor(byte.MaxValue, 228, 225);
public static DotColor Moccasin { get; } = new DotColor(byte.MaxValue, 228, 181);
public static DotColor NavajoWhite { get; } = new DotColor(byte.MaxValue, 222, 173);
public static DotColor Navy { get; } = new DotColor(0, 0, 128);
public static DotColor OldLace { get; } = new DotColor(253, 245, 230);
public static DotColor Olive { get; } = new DotColor(128, 128, 0);
public static DotColor OliveDrab { get; } = new DotColor(107, 142, 35);
public static DotColor Orange { get; } = new DotColor(byte.MaxValue, 165, 0);
public static DotColor OrangeRed { get; } = new DotColor(byte.MaxValue, 69, 0);
public static DotColor Orchid { get; } = new DotColor(218, 112, 214);
public static DotColor PaleGoldenrod { get; } = new DotColor(238, 232, 170);
public static DotColor PaleGreen { get; } = new DotColor(152, 251, 152);
public static DotColor PaleTurquoise { get; } = new DotColor(175, 238, 238);
public static DotColor PaleVioletRed { get; } = new DotColor(219, 112, 147);
public static DotColor PapayaWhip { get; } = new DotColor(byte.MaxValue, 239, 213);
public static DotColor PeachPuff { get; } = new DotColor(byte.MaxValue, 218, 185);
public static DotColor Peru { get; } = new DotColor(205, 133, 63);
public static DotColor Pink { get; } = new DotColor(byte.MaxValue, 192, 203);
public static DotColor Plum { get; } = new DotColor(221, 160, 221);
public static DotColor PowderBlue { get; } = new DotColor(176, 224, 230);
public static DotColor Purple { get; } = new DotColor(128, 0, 128);
public static DotColor Red { get; } = new DotColor(byte.MaxValue, 0, 0);
public static DotColor RosyBrown { get; } = new DotColor(188, 143, 143);
public static DotColor RoyalBlue { get; } = new DotColor(65, 105, 225);
public static DotColor SaddleBrown { get; } = new DotColor(139, 69, 19);
public static DotColor Salmon { get; } = new DotColor(250, 128, 114);
public static DotColor SandyBrown { get; } = new DotColor(244, 164, 96);
public static DotColor SeaGreen { get; } = new DotColor(46, 139, 87);
public static DotColor SeaShell { get; } = new DotColor(byte.MaxValue, 245, 238);
public static DotColor Sienna { get; } = new DotColor(160, 82, 45);
public static DotColor Silver { get; } = new DotColor(192, 192, 192);
public static DotColor SkyBlue { get; } = new DotColor(135, 206, 235);
public static DotColor SlateBlue { get; } = new DotColor(106, 90, 205);
public static DotColor SlateGray { get; } = new DotColor(112, 128, 144);
public static DotColor SlateGrey { get; } = new DotColor(112, 128, 144);
public static DotColor Snow { get; } = new DotColor(byte.MaxValue, 250, 250);
public static DotColor SpringGreen { get; } = new DotColor(0, byte.MaxValue, 127);
public static DotColor SteelBlue { get; } = new DotColor(70, 130, 180);
public static DotColor Tan { get; } = new DotColor(210, 180, 140);
public static DotColor Teal { get; } = new DotColor(0, 128, 128);
public static DotColor Thistle { get; } = new DotColor(216, 191, 216);
public static DotColor Tomato { get; } = new DotColor(byte.MaxValue, 99, 71);
public static DotColor Turquoise { get; } = new DotColor(64, 224, 208);
public static DotColor Violet { get; } = new DotColor(238, 130, 238);
public static DotColor Wheat { get; } = new DotColor(245, 222, 179);
public static DotColor White { get; } = new DotColor(byte.MaxValue, byte.MaxValue, byte.MaxValue);
public static DotColor WhiteSmoke { get; } = new DotColor(245, 245, 245);
public static DotColor Yellow { get; } = new DotColor(byte.MaxValue, byte.MaxValue, 0);
public static DotColor YellowGreen { get; } = new DotColor(154, 205, 50);
public DotColor(byte r, byte g, byte b, byte a = byte.MaxValue)
{
R = r;
G = g;
B = b;
A = a;
}
public bool Equals(DotColor other)
{
if (R == other.R && G == other.G && B == other.B)
{
return A == other.A;
}
return false;
}
public override bool Equals(object obj)
{
if (obj is DotColor other)
{
return Equals(other);
}
return false;
}
public override int GetHashCode()
{
return (((((R.GetHashCode() * 397) ^ G.GetHashCode()) * 397) ^ B.GetHashCode()) * 397) ^ A.GetHashCode();
}
public override string ToString()
{
return $"[DotColor, R:{R}, G:{G}, B:{B}, A:{A}]";
}
public string ToHexString()
{
if (A != byte.MaxValue)
{
return $"#{R:X2}{G:X2}{B:X2}{A:X2}";
}
return $"#{R:X2}{G:X2}{B:X2}";
}
}
internal class DotEdge : DotElement
{
public DotIdentifier From { get; set; }
public DotIdentifier To { get; set; }
public DotColorAttribute Color
{
get
{
return GetAttributeOrDefault<DotColorAttribute>("color");
}
set
{
SetAttribute("color", value);
}
}
public DotEdgeStyleAttribute Style
{
get
{
return GetAttributeOrDefault<DotEdgeStyleAttribute>("style");
}
set
{
SetAttribute("style", value);
}
}
public DotDoubleAttribute PenWidth
{
get
{
return GetAttribute<DotDoubleAttribute>("penwidth");
}
set
{
SetAttribute("penwidth", value);
}
}
public DotEdgeArrowTypeAttribute ArrowHead
{
get
{
return GetAttribute<DotEdgeArrowTypeAttribute>("arrowhead");
}
set
{
SetAttribute("arrowhead", value);
}
}
public DotEdgeArrowTypeAttribute ArrowTail
{
get
{
return GetAttribute<DotEdgeArrowTypeAttribute>("arrowtail");
}
set
{
SetAttribute("arrowtail", value);
}
}
public DotPointAttribute Pos
{
get
{
return GetAttribute<DotPointAttribute>("pos");
}
set
{
SetAttribute("pos", value);
}
}
public override async Task CompileAsync(CompilationContext context)
{
if ((object)From == null || (object)To == null)
{
throw new Exception("Can't compile edge with null From and/or To");
}
await context.WriteIndentationAsync();
await From.CompileAsync(context);
await context.WriteAsync(" " + (context.DirectedGraph ? "->" : "--") + " ");
await To.CompileAsync(context);
if (Attributes.Any())
{
await context.WriteLineAsync(" [");
context.IndentationLevel++;
await CompileAttributesAsync(context);
context.IndentationLevel--;
await context.WriteIndentationAsync();
await context.WriteLineAsync("]");
}
else
{
await context.WriteLineAsync();
}
}
}
internal enum DotEdgeArrowType
{
Normal,
Inv,
Dot,
InvDot,
ODot,
InvODot,
None,
Tee,
Empty,
InvEmpty,
Diamond,
ODiamond,
EDiamond,
Crow,
Box,
OBox,
Open,
HalfOpen,
Vee
}
[Flags]
internal enum DotEdgeStyle
{
Solid = 1,
Dashed = 2,
Dotted = 4,
Bold = 8,
Tapered = 0x10,
Invis = 0x20
}
internal abstract class DotElement : IDotElement
{
protected readonly Dictionary<string, IDotAttribute> Attributes = new Dictionary<string, IDotAttribute>();
public DotLabelAttribute Label
{
get
{
return GetAttributeOrDefault<DotLabelAttribute>("label");
}
set
{
SetAttribute("label", value);
}
}
public DotColorAttribute FontColor
{
get
{
return GetAttributeOrDefault<DotColorAttribute>("fontcolor");
}
set
{
SetAttribute("fontcolor", value);
}
}
public bool HasAttribute(string name)
{
return Attributes.ContainsKey(name);
}
public IDotAttribute GetAttribute(string name)
{
if (Attributes.TryGetValue(name, out var value))
{
return value;
}
throw new Exception("There is no attribute named '" + name + "'");
}
public IDotAttribute GetAttributeOrDefault(string name, IDotAttribute defaultValue = null)
{
if (Attributes.TryGetValue(name, out var value))
{
return value;
}
return defaultValue;
}
public T GetAttribute<T>(string name) where T : IDotAttribute
{
IDotAttribute attribute = GetAttribute(name);
if (attribute is T)
{
return (T)attribute;
}
throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {attribute.GetType()})");
}
public T GetAttributeOrDefault<T>(string name, T defaultValue = default(T)) where T : IDotAttribute
{
if (Attributes.TryGetValue(name, out var value))
{
if (value is T)
{
return (T)value;
}
throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {value.GetType()})");
}
return defaultValue;
}
public bool TryGetAttribute(string name, out IDotAttribute attribute)
{
if (Attributes.TryGetValue(name, out var value))
{
attribute = value;
return true;
}
attribute = null;
return false;
}
public bool TryGetAttribute<T>(string name, out T attribute) where T : IDotAttribute
{
if (!TryGetAttribute(name, out var attribute2))
{
attribute = default(T);
return false;
}
if (attribute2 is T val)
{
attribute = val;
return true;
}
throw new Exception($"Attribute with name '{name}' doesn't match the expected type (expected: {typeof(T)}, current: {attribute2.GetType()})");
}
public void SetAttribute(string name, IDotAttribute value)
{
if (value == null)
{
RemoveAttribute(name);
}
else
{
Attributes[name] = value;
}
}
public bool RemoveAttribute(string name)
{
return Attributes.Remove(name);
}
protected async Task CompileAttributesAsync(CompilationContext context)
{
foreach (KeyValuePair<string, IDotAttribute> attributePair in Attributes)
{
await context.WriteIndentationAsync();
await context.WriteAsync("\"" + attributePair.Key + "\"=");
await attributePair.Value.CompileAsync(context);
await context.WriteLineAsync();
}
}
public abstract Task CompileAsync(CompilationContext context);
}
internal class DotGraph : DotBaseGraph
{
public bool Strict { get; set; }
public bool Directed { get; set; }
public override async Task CompileAsync(CompilationContext context)
{
context.DirectedGraph = Directed;
await context.WriteIndentationAsync();
if (Strict)
{
await context.WriteAsync("strict ");
}
await context.WriteAsync(Directed ? "digraph " : "graph ");
await CompileBodyAsync(context);
}
}
internal class DotIdentifier : IDotElement, IEquatable<DotIdentifier>
{
private static readonly Regex NoQuotesRequiredRegex = new Regex("^([a-zA-Z\\200-\\377_][a-zA-Z\\200-\\3770-9_]*|[-]?(.[0-9]+|[0-9]+(.[0-9]+)?))$");
private static readonly string[] ReservedWords = new string[6] { "graph", "digraph", "subgraph", "strict", "node", "edge" };
public string Value { get; set; }
public bool IsHtml { get; set; }
public DotIdentifier(string value, bool isHtml = false)
{
Value = value;
IsHtml = isHtml;
}
public async Task CompileAsync(CompilationContext context)
{
if (IsHtml)
{
await context.TextWriter.WriteAsync("<" + Value + ">");
return;
}
string text = (context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value);
if (RequiresDoubleQuotes(text))
{
await context.TextWriter.WriteAsync("\"" + text + "\"");
}
else
{
await context.TextWriter.WriteAsync(text ?? "");
}
}
private static bool RequiresDoubleQuotes(string value)
{
if (!ReservedWords.Contains(value))
{
return !NoQuotesRequiredRegex.IsMatch(value);
}
return true;
}
public bool Equals(DotIdentifier other)
{
if ((object)other == null)
{
return false;
}
if ((object)this == other)
{
return true;
}
if (Value == other.Value)
{
return IsHtml == other.IsHtml;
}
return false;
}
public override bool Equals(object obj)
{
if (obj == null)
{
return false;
}
if (this == obj)
{
return true;
}
if (obj.GetType() != GetType())
{
return false;
}
return Equals((DotIdentifier)obj);
}
public override int GetHashCode()
{
return (((Value != null) ? Value.GetHashCode() : 0) * 397) ^ IsHtml.GetHashCode();
}
public static bool operator ==(DotIdentifier identifier1, DotIdentifier identifier2)
{
return identifier1?.Equals(identifier2) ?? ((object)identifier2 == null);
}
public static bool operator !=(DotIdentifier identifier1, DotIdentifier identifier2)
{
return !(identifier1 == identifier2);
}
}
internal class DotNode : DotElement
{
public DotIdentifier Identifier { get; set; }
public DotColorAttribute Color
{
get
{
return GetAttributeOrDefault<DotColorAttribute>("color");
}
set
{
SetAttribute("color", value);
}
}
public DotColorAttribute FillColor
{
get
{
return GetAttributeOrDefault<DotColorAttribute>("fillcolor");
}
set
{
SetAttribute("fillcolor", value);
}
}
public DotNodeShapeAttribute Shape
{
get
{
return GetAttributeOrDefault<DotNodeShapeAttribute>("shape");
}
set
{
SetAttribute("shape", value);
}
}
public DotNodeStyleAttribute Style
{
get
{
return GetAttributeOrDefault<DotNodeStyleAttribute>("style");
}
set
{
SetAttribute("style", value);
}
}
public DotDoubleAttribute Width
{
get
{
return GetAttribute<DotDoubleAttribute>("width");
}
set
{
SetAttribute("width", value);
}
}
public DotDoubleAttribute Height
{
get
{
return GetAttribute<DotDoubleAttribute>("height");
}
set
{
SetAttribute("height", value);
}
}
public DotDoubleAttribute PenWidth
{
get
{
return GetAttribute<DotDoubleAttribute>("penwidth");
}
set
{
SetAttribute("penwidth", value);
}
}
public DotPointAttribute Pos
{
get
{
return GetAttribute<DotPointAttribute>("pos");
}
set
{
SetAttribute("pos", value);
}
}
public override async Task CompileAsync(CompilationContext context)
{
await context.WriteIndentationAsync();
await Identifier.CompileAsync(context);
if (Attributes.Any())
{
await context.WriteLineAsync(" [");
context.IndentationLevel++;
await CompileAttributesAsync(context);
context.IndentationLevel--;
await context.WriteIndentationAsync();
await context.WriteLineAsync("]");
}
else
{
await context.WriteLineAsync();
}
}
}
internal enum DotNodeShape
{
Box,
Polygon,
Ellipse,
Oval,
Circle,
Point,
Egg,
Triangle,
PlainText,
Plain,
Diamond,
Trapezium,
Parallelogram,
House,
Pentagon,
Hexagon,
Septagon,
Octagon,
DoubleCircle,
DoubleOctagon,
TripleOctagon,
InvTriangle,
InvTrapezium,
InvHouse,
MDiamond,
MSquare,
MCircle,
Rect,
Rectangle,
Square,
Star,
None,
Underline,
Cylinder,
Note,
Tab,
Folder,
Box3D,
Component,
Promoter,
CDS,
Terminator,
UTR,
PrimerSite,
RestrictionSite,
FivePOverHang,
ThreePOveHang,
NOverHang,
Assembly,
Signature,
Insulator,
Ribosite,
RNasTab,
ProteaseSite,
ProteinsTab,
RPromoter,
RArrow,
LArrow,
LPromoter
}
[Flags]
internal enum DotNodeStyle
{
Solid = 1,
Dashed = 2,
Dotted = 4,
Bold = 8,
Rounded = 0x10,
Diagonals = 0x20,
Filled = 0x40,
Striped = 0x80,
Wedged = 0x100,
Invis = 0x200
}
internal struct DotPoint
{
public int X;
public int Y;
public int? Z;
public bool Fixed;
public DotPoint(int x, int y, bool @fixed = false)
{
X = x;
Y = y;
Z = null;
Fixed = @fixed;
}
public DotPoint(int x, int y, int z, bool @fixed = false)
{
X = x;
Y = y;
Z = z;
Fixed = @fixed;
}
public override string ToString()
{
string text = $"{X},{Y}";
if (Z.HasValue)
{
text += $",{Z}";
}
if (Fixed)
{
text += "!";
}
return text;
}
}
internal enum DotRankDir
{
TB,
BT,
LR,
RL
}
internal class DotSubgraph : DotBaseGraph
{
public DotColorAttribute Color
{
get
{
return GetAttributeOrDefault<DotColorAttribute>("color");
}
set
{
SetAttribute("color", value);
}
}
public DotSubgraphStyleAttribute Style
{
get
{
return GetAttributeOrDefault<DotSubgraphStyleAttribute>("style");
}
set
{
SetAttribute("style", value);
}
}
public override async Task CompileAsync(CompilationContext context)
{
await context.WriteIndentationAsync();
await context.WriteAsync("subgraph ");
await CompileBodyAsync(context);
}
}
[Flags]
internal enum DotSubgraphStyle
{
Solid = 1,
Dashed = 2,
Dotted = 4,
Bold = 8,
Rounded = 0x10,
Filled = 0x20,
Striped = 0x40,
Invis = 0x80
}
internal interface IDotElement
{
Task CompileAsync(CompilationContext context);
}
}
namespace DotNetGraph.Compilation
{
internal class CompilationContext
{
public TextWriter TextWriter { get; }
public CompilationOptions Options { get; }
public int IndentationLevel { get; set; }
public bool DirectedGraph { get; set; }
public CompilationContext(TextWriter textWriter, CompilationOptions options)
{
TextWriter = textWriter;
Options = options;
IndentationLevel = 0;
DirectedGraph = false;
}
public async Task WriteIndentationAsync()
{
if (Options.Indented)
{
for (int i = 0; i < IndentationLevel; i++)
{
await TextWriter.WriteAsync("\t");
}
}
}
public async Task WriteAsync(string value)
{
await TextWriter.WriteAsync(value);
}
public async Task WriteLineAsync(string value = null)
{
await TextWriter.WriteAsync(value);
await TextWriter.WriteAsync(Options.Indented ? '\n' : ' ');
}
}
internal class CompilationOptions
{
public bool AutomaticEscapedCharactersFormat { get; set; } = true;
public bool Indented { get; set; } = true;
}
}
namespace DotNetGraph.Attributes
{
internal class DotAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotAttribute(string value)
{
Value = value;
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync(Value);
}
}
internal class DotColorAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotColorAttribute(DotColor color)
{
Value = color.ToHexString();
}
public DotColorAttribute(string value)
{
Value = value;
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotColorAttribute(DotColor value)
{
return new DotColorAttribute(value);
}
public static implicit operator DotColorAttribute(string value)
{
return new DotColorAttribute(value);
}
}
internal class DotDoubleAttribute : IDotAttribute, IDotElement
{
public double Value { get; set; }
public string Format { get; set; }
public DotDoubleAttribute(double value, string format = "F2")
{
Value = value;
Format = format;
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync(Value.ToString(Format, NumberFormatInfo.InvariantInfo));
}
public static implicit operator DotDoubleAttribute(double value)
{
return new DotDoubleAttribute(value);
}
}
internal class DotEdgeArrowTypeAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotEdgeArrowTypeAttribute(string value)
{
Value = value;
}
public DotEdgeArrowTypeAttribute(DotEdgeArrowType type)
{
Value = type.ToString().ToLowerInvariant();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotEdgeArrowTypeAttribute(DotEdgeArrowType value)
{
return new DotEdgeArrowTypeAttribute(value);
}
public static implicit operator DotEdgeArrowTypeAttribute(string value)
{
return new DotEdgeArrowTypeAttribute(value);
}
}
internal class DotEdgeStyleAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotEdgeStyleAttribute(string value)
{
Value = value;
}
public DotEdgeStyleAttribute(DotEdgeStyle style)
{
Value = style.FlagsToString();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotEdgeStyleAttribute(DotEdgeStyle value)
{
return new DotEdgeStyleAttribute(value);
}
public static implicit operator DotEdgeStyleAttribute(string value)
{
return new DotEdgeStyleAttribute(value);
}
}
internal class DotLabelAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public bool IsHtml { get; set; }
public DotLabelAttribute(string value, bool isHtml = false)
{
Value = value;
IsHtml = isHtml;
}
public async Task CompileAsync(CompilationContext context)
{
if (IsHtml)
{
await context.TextWriter.WriteAsync("<" + Value + ">");
return;
}
string text = (context.Options.AutomaticEscapedCharactersFormat ? Value.FormatGraphvizEscapedCharacters() : Value);
await context.TextWriter.WriteAsync("\"" + text + "\"");
}
public static implicit operator DotLabelAttribute(string value)
{
return new DotLabelAttribute(value);
}
}
internal class DotNodeShapeAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotNodeShapeAttribute(string value)
{
Value = value;
}
public DotNodeShapeAttribute(DotNodeShape shape)
{
Value = shape.ToString().ToLowerInvariant();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotNodeShapeAttribute(DotNodeShape value)
{
return new DotNodeShapeAttribute(value);
}
public static implicit operator DotNodeShapeAttribute(string value)
{
return new DotNodeShapeAttribute(value);
}
}
internal class DotNodeStyleAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotNodeStyleAttribute(string value)
{
Value = value;
}
public DotNodeStyleAttribute(DotNodeStyle style)
{
Value = style.FlagsToString();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotNodeStyleAttribute(DotNodeStyle value)
{
return new DotNodeStyleAttribute(value);
}
public static implicit operator DotNodeStyleAttribute(string value)
{
return new DotNodeStyleAttribute(value);
}
}
internal class DotPointAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotPointAttribute(string value)
{
Value = value;
}
public DotPointAttribute(DotPoint point)
{
Value = point.ToString();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync(Value);
}
public static implicit operator DotPointAttribute(DotPoint value)
{
return new DotPointAttribute(value);
}
public static implicit operator DotPointAttribute(string value)
{
return new DotPointAttribute(value);
}
}
internal class DotRankDirAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotRankDirAttribute(string value)
{
Value = value;
}
public DotRankDirAttribute(DotRankDir rankDir)
{
Value = rankDir.ToString();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotRankDirAttribute(DotRankDir value)
{
return new DotRankDirAttribute(value);
}
public static implicit operator DotRankDirAttribute(string value)
{
return new DotRankDirAttribute(value);
}
}
internal class DotSubgraphStyleAttribute : IDotAttribute, IDotElement
{
public string Value { get; set; }
public DotSubgraphStyleAttribute(string value)
{
Value = value;
}
public DotSubgraphStyleAttribute(DotSubgraphStyle style)
{
Value = style.FlagsToString();
}
public async Task CompileAsync(CompilationContext context)
{
await context.WriteAsync("\"" + Value + "\"");
}
public static implicit operator DotSubgraphStyleAttribute(DotSubgraphStyle value)
{
return new DotSubgraphStyleAttribute(value);
}
public static implicit operator DotSubgraphStyleAttribute(string value)
{
return new DotSubgraphStyleAttribute(value);
}
}
internal interface IDotAttribute : IDotElement
{
}
}