//Returns any nodes that are created public IEnumerable <ProductionNode> CreateOrLinkAllPossibleRecipeNodes(ProductionNode node) { List <ProductionNode> createdNodes = new List <ProductionNode>(); foreach (Item item in node.Inputs) { var recipePool = item.Recipes.Where(r => !r.IsCyclic); //Ignore recipes that can ultimately supply themselves, like filling/emptying barrels or certain modded recipes foreach (Recipe recipe in recipePool.Where(r => r.Enabled)) { var existingNodes = Nodes.OfType <RecipeNode>().Where(n => n.BaseRecipe == recipe); if (!existingNodes.Any()) { RecipeNode newNode = RecipeNode.Create(recipe, this); NodeLink.Create(newNode, node, item); createdNodes.Add(newNode); } else { foreach (RecipeNode existingNode in existingNodes) { NodeLink.Create(existingNode, node, item); } } } } return(createdNodes); }
public void AutoSatisfyNodeDemand(ProductionNode node, Item item) { if (node.InputLinks.Any(l => l.Item == item)) //Increase throughput of existing node link { NodeLink link = node.InputLinks.First(l => l.Item == item); //link.Amount += node.GetExcessDemand(item); } else if (Nodes.Any(n => n.Outputs.Contains(item))) //Add link from existing node { ProductionNode existingNode = Nodes.Find(n => n.Outputs.Contains(item)); NodeLink.Create(existingNode, node, item); } else if (item.Recipes.Any(r => !CyclicRecipes.Contains(r))) //Create new recipe node and link from it { RecipeNode newNode = RecipeNode.Create(item.Recipes.First(r => !CyclicRecipes.Contains(r)), this); NodeLink.Create(newNode, node, item); } else //Create new supply node and link from it { SupplyNode newNode = SupplyNode.Create(item, this); NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item)); } ReplaceCycles(); }
public static RecipeNode Create(Recipe baseRecipe, ProductionGraph graph) { RecipeNode node = new RecipeNode(baseRecipe, graph); node.Graph.Nodes.Add(node); node.Graph.InvalidateCaches(); return(node); }
private void AddItemButton_Click(object sender, EventArgs e) { foreach (ListViewItem lvItem in ItemListView.SelectedItems) { Item item = (Item)lvItem.Tag; NodeElement newElement = null; var itemSupplyOption = new ItemChooserControl(item, "Create infinite supply node", item.FriendlyName); var itemOutputOption = new ItemChooserControl(item, "Create output node", item.FriendlyName); var optionList = new List <ChooserControl>(); optionList.Add(itemOutputOption); foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled)) { if (recipe.Results.ContainsKey(item)) { optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName)); } } optionList.Add(itemSupplyOption); foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled)) { if (recipe.Ingredients.ContainsKey(item)) { optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName)); } } var chooserPanel = new ChooserPanel(optionList, GraphViewer); Point location = GraphViewer.ScreenToGraph(new Point(GraphViewer.Width / 2, GraphViewer.Height / 2)); chooserPanel.Show(c => { if (c != null) { if (c == itemSupplyOption) { newElement = new NodeElement(SupplyNode.Create(item, GraphViewer.Graph), GraphViewer); } else if (c is RecipeChooserControl) { newElement = new NodeElement(RecipeNode.Create((c as RecipeChooserControl).DisplayedRecipe, GraphViewer.Graph), GraphViewer); } else if (c == itemOutputOption) { newElement = new NodeElement(ConsumerNode.Create(item, GraphViewer.Graph), GraphViewer); } newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); } }); } GraphViewer.Graph.UpdateNodeValues(); }
private void AddRecipeButton_Click(object sender, EventArgs e) { foreach (ListViewItem lvItem in RecipeListView.SelectedItems) { Point location = GraphViewer.ScreenToGraph(new Point(GraphViewer.Width / 2, GraphViewer.Height / 2)); NodeElement newElement = new NodeElement(RecipeNode.Create((Recipe)lvItem.Tag, GraphViewer.Graph), GraphViewer); newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); } GraphViewer.Graph.UpdateNodeValues(); }
public NodeElement(ProductionNode displayedNode, ProductionGraphViewModel parent) { Parent = parent; HorizontalAlignment = HorizontalAlignment.Center; VerticalAlignment = VerticalAlignment.Center; DisplayedNode = displayedNode; Initialize(displayedNode); BackgroundColor = DisplayedNode switch { ConsumerNode consumer => consumer.ConsumedItem.IsMissingItem ? MissingColor : SupplyColor, SupplyNode supplier => supplier.SuppliedItem.IsMissingItem ? MissingColor : ConsumerColor, RecipeNode recipe => recipe.BaseRecipe.IsMissingRecipe ? MissingColor : RecipeColor, PassthroughNode passthrough => passthrough.PassedItem.IsMissingItem ? MissingColor : PassthroughColor, _ => throw new ArgumentException("No branch for node: " + DisplayedNode) }; }
public void LoadFromJson(JObject json) { Graph.Nodes.Clear(); Elements.Clear(); //Has to go first, as all other data depends on which mods are loaded List <String> EnabledMods = json["EnabledMods"].Select(t => (String)t).ToList(); foreach (Mod mod in DataCache.Mods) { mod.Enabled = EnabledMods.Contains(mod.Name); } List <String> enabledMods = DataCache.Mods.Where(m => m.Enabled).Select(m => m.Name).ToList(); using (ProgressForm form = new ProgressForm(enabledMods)) { form.ShowDialog(); } Graph.SelectedAmountType = (AmountType)(int)json["AmountType"]; Graph.SelectedUnit = (RateUnit)(int)json["Unit"]; List <JToken> nodes = json["Nodes"].ToList <JToken>(); foreach (var node in nodes) { ProductionNode newNode = null; switch ((String)node["NodeType"]) { case "Consumer": { String itemName = (String)node["ItemName"]; if (DataCache.Items.ContainsKey(itemName)) { Item item = DataCache.Items[itemName]; newNode = ConsumerNode.Create(item, Graph); } else { Item missingItem = new Item(itemName); missingItem.IsMissingItem = true; newNode = ConsumerNode.Create(missingItem, Graph); } break; } case "Supply": { String itemName = (String)node["ItemName"]; if (DataCache.Items.ContainsKey(itemName)) { Item item = DataCache.Items[itemName]; newNode = SupplyNode.Create(item, Graph); } else { Item missingItem = new Item(itemName); missingItem.IsMissingItem = true; DataCache.Items.Add(itemName, missingItem); newNode = SupplyNode.Create(missingItem, Graph); } break; } case "PassThrough": { String itemName = (String)node["ItemName"]; if (DataCache.Items.ContainsKey(itemName)) { Item item = DataCache.Items[itemName]; newNode = PassthroughNode.Create(item, Graph); } else { Item missingItem = new Item(itemName); missingItem.IsMissingItem = true; DataCache.Items.Add(itemName, missingItem); newNode = PassthroughNode.Create(missingItem, Graph); } break; } case "Recipe": { String recipeName = (String)node["RecipeName"]; if (DataCache.Recipes.ContainsKey(recipeName)) { Recipe recipe = DataCache.Recipes[recipeName]; newNode = RecipeNode.Create(recipe, Graph); } else { Recipe missingRecipe = new Recipe(recipeName, 0f, new Dictionary <Item, float>(), new Dictionary <Item, float>()); missingRecipe.IsMissingRecipe = true; DataCache.Recipes.Add(recipeName, missingRecipe); newNode = RecipeNode.Create(missingRecipe, Graph); } if (node["Assembler"] != null) { var assemblerKey = (String)node["Assembler"]; if (DataCache.Assemblers.ContainsKey(assemblerKey)) { (newNode as RecipeNode).Assembler = DataCache.Assemblers[assemblerKey]; } } (newNode as RecipeNode).NodeModules = ModuleSelector.Load(node); break; } default: { Trace.Fail("Unknown node type: " + node["NodeType"]); break; } } if (newNode != null) { newNode.rateType = (RateType)(int)node["RateType"]; if (newNode.rateType == RateType.Manual) { if (node["DesiredRate"] != null) { newNode.desiredRate = (float)node["DesiredRate"]; } else { // Legacy data format stored desired rate in actual newNode.desiredRate = (float)node["ActualRate"]; } } if (node["SpeedBonus"] != null) { newNode.SpeedBonus = Math.Round((float)node["SpeedBonus"], 4); } if (node["ProductivityBonus"] != null) { newNode.ProductivityBonus = Math.Round((float)node["ProductivityBonus"], 4); } } } List <JToken> nodeLinks = json["NodeLinks"].ToList <JToken>(); foreach (var nodelink in nodeLinks) { ProductionNode supplier = Graph.Nodes[(int)nodelink["Supplier"]]; ProductionNode consumer = Graph.Nodes[(int)nodelink["Consumer"]]; String itemName = (String)nodelink["Item"]; if (!DataCache.Items.ContainsKey(itemName)) { Item missingItem = new Item(itemName); missingItem.IsMissingItem = true; DataCache.Items.Add(itemName, missingItem); } Item item = DataCache.Items[itemName]; NodeLink.Create(supplier, consumer, item); } IEnumerable <String> EnabledAssemblers = json["EnabledAssemblers"].Select(t => (String)t); foreach (Assembler assembler in DataCache.Assemblers.Values) { assembler.Enabled = EnabledAssemblers.Contains(assembler.Name); } IEnumerable <String> EnabledMiners = json["EnabledMiners"].Select(t => (String)t); foreach (Miner miner in DataCache.Miners.Values) { miner.Enabled = EnabledMiners.Contains(miner.Name); } IEnumerable <String> EnabledModules = json["EnabledModules"].Select(t => (String)t); foreach (Module module in DataCache.Modules.Values) { module.Enabled = EnabledModules.Contains(module.Name); } JToken enabledRecipesToken; if (json.TryGetValue("EnabledRecipes", out enabledRecipesToken)) { IEnumerable <String> EnabledRecipes = enabledRecipesToken.Select(t => (String)t); foreach (Recipe recipe in DataCache.Recipes.Values) { recipe.Enabled = EnabledRecipes.Contains(recipe.Name); } } Graph.UpdateNodeValues(); AddRemoveElements(); List <String> ElementLocations = json["ElementLocations"].Select(l => (String)l).ToList(); for (int i = 0; i < ElementLocations.Count; i++) { int[] splitPoint = ElementLocations[i].Split(',').Select(s => Convert.ToInt32(s)).ToArray(); GraphElement element = GetElementForNode(Graph.Nodes[i]); element.Location = new Point(splitPoint[0], splitPoint[1]); } LimitViewToBounds(); }
void HandleItemDropping(object sender, DragEventArgs e) { if (GhostDragElement != null) { if (e.Data.GetDataPresent(typeof(HashSet <Item>))) { foreach (Item item in GhostDragElement.Items) { NodeElement newElement = null; var itemSupplyOption = new ItemChooserControl(item, "Create infinite supply node", item.FriendlyName); var itemOutputOption = new ItemChooserControl(item, "Create output node", item.FriendlyName); var itemPassthroughOption = new ItemChooserControl(item, "Create pass-through node", item.FriendlyName); var optionList = new List <ChooserControl>(); optionList.Add(itemPassthroughOption); optionList.Add(itemOutputOption); foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Enabled)) { if (recipe.Results.ContainsKey(item) && recipe.Category != "incinerator" && recipe.Category != "incineration") { optionList.Add(new RecipeChooserControl(recipe, String.Format("Create '{0}' recipe node", recipe.FriendlyName), recipe.FriendlyName)); } } optionList.Add(itemSupplyOption); var chooserPanel = new ChooserPanel(optionList, this); Point location = GhostDragElement.Location; chooserPanel.Show(c => { if (c != null) { if (c == itemSupplyOption) { newElement = new NodeElement(SupplyNode.Create(item, this.Graph), this); } else if (c is RecipeChooserControl) { newElement = new NodeElement(RecipeNode.Create((c as RecipeChooserControl).DisplayedRecipe, this.Graph), this); } else if (c == itemPassthroughOption) { newElement = new NodeElement(PassthroughNode.Create(item, this.Graph), this); } else if (c == itemOutputOption) { newElement = new NodeElement(ConsumerNode.Create(item, this.Graph), this); } else { Trace.Fail("No handler for selected item"); } Graph.UpdateNodeValues(); newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); } }); } } else if (e.Data.GetDataPresent(typeof(HashSet <Recipe>))) { foreach (Recipe recipe in GhostDragElement.Recipes) { NodeElement newElement = new NodeElement(RecipeNode.Create(recipe, Graph), this); Graph.UpdateNodeValues(); newElement.Update(); newElement.Location = Point.Add(GhostDragElement.Location, new Size(-newElement.Width / 2, -newElement.Height / 2)); } } GhostDragElement.Dispose(); } }
public static RecipeNode Create(Recipe baseRecipe, ProductionGraph graph) { RecipeNode node = new RecipeNode(baseRecipe, graph); node.Graph.Nodes.Add(node); node.Graph.InvalidateCaches(); return node; }
private void EndDrag(Point location) { if (SupplierElement != null && ConsumerElement != null) { if (StartConnectionType == LinkType.Input) { NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item); } else { NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item); } } else if (StartConnectionType == LinkType.Output && ConsumerElement == null) { List <ChooserControl> recipeOptionList = new List <ChooserControl>(); var itemOutputOption = new ItemChooserControl(Item, "Create output node", Item.FriendlyName); var itemPassthroughOption = new ItemChooserControl(Item, "Create pass-through node", Item.FriendlyName); recipeOptionList.Add(itemOutputOption); recipeOptionList.Add(itemPassthroughOption); foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Ingredients.Keys.Contains(Item) && r.Enabled && r.Category != "incinerator" && r.Category != "incineration")) { recipeOptionList.Add(new RecipeChooserControl(recipe, "Use recipe " + recipe.FriendlyName, recipe.FriendlyName)); } var chooserPanel = new ChooserPanel(recipeOptionList, Parent); chooserPanel.Show(c => { if (c != null) { NodeElement newElement = null; if (c is RecipeChooserControl) { Recipe selectedRecipe = (c as RecipeChooserControl).DisplayedRecipe; newElement = new NodeElement(RecipeNode.Create(selectedRecipe, Parent.Graph), Parent); } else if (c == itemOutputOption) { Item selectedItem = (c as ItemChooserControl).DisplayedItem; newElement = new NodeElement(ConsumerNode.Create(selectedItem, Parent.Graph), Parent); (newElement.DisplayedNode as ConsumerNode).rateType = RateType.Auto; } else if (c == itemPassthroughOption) { Item selectedItem = (c as ItemChooserControl).DisplayedItem; newElement = new NodeElement(PassthroughNode.Create(selectedItem, Parent.Graph), Parent); (newElement.DisplayedNode as PassthroughNode).rateType = RateType.Auto; } else { Trace.Fail("Unhandled option: " + c.ToString()); } newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); new LinkElement(Parent, NodeLink.Create(SupplierElement.DisplayedNode, newElement.DisplayedNode, Item)); } Parent.Graph.UpdateNodeValues(); Parent.AddRemoveElements(); Parent.UpdateNodes(); }); } else if (StartConnectionType == LinkType.Input && SupplierElement == null) { List <ChooserControl> recipeOptionList = new List <ChooserControl>(); var itemSupplyOption = new ItemChooserControl(Item, "Create infinite supply node", Item.FriendlyName); var itemPassthroughOption = new ItemChooserControl(Item, "Create pass-through node", Item.FriendlyName); recipeOptionList.Add(itemSupplyOption); recipeOptionList.Add(itemPassthroughOption); foreach (Recipe recipe in DataCache.Recipes.Values.Where(r => r.Results.Keys.Contains(Item) && r.Enabled && r.Category != "incinerator" && r.Category != "incineration")) { if (recipe.Category != "incinerator" && recipe.Category != "incineration") { recipeOptionList.Add(new RecipeChooserControl(recipe, "Use recipe " + recipe.FriendlyName, recipe.FriendlyName)); } } var chooserPanel = new ChooserPanel(recipeOptionList, Parent); chooserPanel.Show(c => { if (c != null) { NodeElement newElement = null; if (c is RecipeChooserControl) { Recipe selectedRecipe = (c as RecipeChooserControl).DisplayedRecipe; newElement = new NodeElement(RecipeNode.Create(selectedRecipe, Parent.Graph), Parent); } else if (c == itemSupplyOption) { Item selectedItem = (c as ItemChooserControl).DisplayedItem; newElement = new NodeElement(SupplyNode.Create(selectedItem, Parent.Graph), Parent); } else if (c == itemPassthroughOption) { Item selectedItem = (c as ItemChooserControl).DisplayedItem; newElement = new NodeElement(PassthroughNode.Create(selectedItem, Parent.Graph), Parent); (newElement.DisplayedNode as PassthroughNode).rateType = RateType.Auto; } else { Trace.Fail("Unhandled option: " + c.ToString()); } newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); new LinkElement(Parent, NodeLink.Create(newElement.DisplayedNode, ConsumerElement.DisplayedNode, Item)); } Parent.Graph.UpdateNodeValues(); Parent.AddRemoveElements(); Parent.UpdateNodes(); }); } Parent.Graph.UpdateNodeValues(); Parent.AddRemoveElements(); Parent.UpdateNodes(); Dispose(); }
private void EndDrag(Point location) { if (SupplierElement != null && ConsumerElement != null) { if (StartConnectionType == LinkType.Input) { NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, ConsumerElement.DisplayedNode.GetUnsatisfiedDemand(Item)); } else { NodeLink.Create(SupplierElement.DisplayedNode, ConsumerElement.DisplayedNode, Item, SupplierElement.DisplayedNode.GetExcessOutput(Item)); } } else if (StartConnectionType == LinkType.Output && ConsumerElement == null) { using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Ingredients.Keys.Contains(Item)), new List <Item> { Item }, "Create output node", "Use recipe {0}")) { var result = form.ShowDialog(); if (result == DialogResult.OK) { NodeElement newElement = null; if (form.selectedRecipe != null) { newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent); } else if (form.selectedItem != null) { newElement = new NodeElement(ConsumerNode.Create(form.selectedItem, Parent.Graph), Parent); } newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); new LinkElement(Parent, NodeLink.Create(SupplierElement.DisplayedNode, newElement.DisplayedNode, Item)); } } } else if (StartConnectionType == LinkType.Input && SupplierElement == null) { using (var form = new RecipeChooserForm(DataCache.Recipes.Values.Where(r => r.Results.Keys.Contains(Item)), new List <Item> { Item }, "Create infinite supply node", "Use recipe {0}")) { var result = form.ShowDialog(); if (result == DialogResult.OK) { NodeElement newElement = null; if (form.selectedRecipe != null) { newElement = new NodeElement(RecipeNode.Create(form.selectedRecipe, Parent.Graph), Parent); } else if (form.selectedItem != null) { newElement = new NodeElement(SupplyNode.Create(form.selectedItem, Parent.Graph), Parent); } newElement.Update(); newElement.Location = Point.Add(location, new Size(-newElement.Width / 2, -newElement.Height / 2)); new LinkElement(Parent, NodeLink.Create(newElement.DisplayedNode, ConsumerElement.DisplayedNode, Item)); } } } Parent.AddRemoveElements(); Parent.UpdateNodes(); Dispose(); }
public void CreateRecipeNodeToSatisfyItemDemand(ProductionNode node, Item item, Recipe recipe) { RecipeNode newNode = RecipeNode.Create(recipe, this); NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item)); }
public void Update() { UpdateTabOrder(); if (DisplayedNode is SupplyNode) { SupplyNode node = (SupplyNode)DisplayedNode; if (!Parent.ShowMiners) { if (node.SuppliedItem.IsMissingItem) { text = String.Format("Item not loaded! ({0})", node.DisplayName); } else { text = "Input: " + node.SuppliedItem.FriendlyName; } } else { text = ""; } } else if (DisplayedNode is ConsumerNode) { ConsumerNode node = (ConsumerNode)DisplayedNode; if (node.ConsumedItem.IsMissingItem) { text = String.Format("Item not loaded! ({0})", node.DisplayName); } else { text = "Output: " + node.ConsumedItem.FriendlyName; } } else if (DisplayedNode is RecipeNode) { RecipeNode node = (RecipeNode)DisplayedNode; if (!Parent.ShowAssemblers) { if (node.BaseRecipe.IsMissingRecipe) { text = String.Format("Recipe not loaded! ({0})", node.DisplayName); } else { text = "Recipe: " + node.BaseRecipe.FriendlyName; } } else { text = ""; } } Graphics graphics = Parent.CreateGraphics(); int minWidth = (int)graphics.MeasureString(text, size10Font).Width; Width = Math.Max(75, getIconWidths()); Width = Math.Max(Width, minWidth); if (assemblerBox != null) { if ((DisplayedNode is RecipeNode && Parent.ShowAssemblers) || (DisplayedNode is SupplyNode && Parent.ShowMiners)) { Height = 120; if (DisplayedNode is RecipeNode) { var assemblers = (DisplayedNode as RecipeNode).GetAssemblers(); if (Parent.Graph.SelectedAmountType == AmountType.FixedAmount) { assemblers = assemblers.ToDictionary(p => p.Key, p => 0); } assemblerBox.AssemblerList = assemblers; } else if (DisplayedNode is SupplyNode) { assemblerBox.AssemblerList = (DisplayedNode as SupplyNode).GetMinimumMiners(); } assemblerBox.Update(); Width = Math.Max(Width, assemblerBox.Width + 20); Height = assemblerBox.Height + 80; assemblerBox.X = (Width - assemblerBox.Width) / 2 + 2; assemblerBox.Y = (Height - assemblerBox.Height) / 2 + 2; } else { assemblerBox.AssemblerList.Clear(); Width = Math.Max(100, Width); Height = 90; assemblerBox.Update(); } } else { Height = 90; } foreach (ItemTab tab in inputTabs.Union(outputTabs)) { tab.FillColour = chooseIconColour(tab.Item, tab.Type); tab.Text = getIconString(tab.Item, tab.Type); } UpdateTabOrder(); }