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(); }
//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); }
//Returns any nodes that are created public IEnumerable <ProductionNode> CreateOrLinkAllPossibleSupplyNodes(ProductionNode node) { List <ProductionNode> createdNodes = new List <ProductionNode>(); var unlinkedItems = node.Inputs.Where(i => !node.InputLinks.Any(nl => nl.Item == i)); foreach (Item item in unlinkedItems) { var existingNodes = Nodes.OfType <SupplyNode>().Where(n => n.SuppliedItem == item); if (!existingNodes.Any()) { SupplyNode newNode = SupplyNode.Create(item, this); NodeLink.Create(newNode, node, item); createdNodes.Add(newNode); } else { foreach (SupplyNode existingNode in existingNodes) { NodeLink.Create(existingNode, node, item); } } } return(createdNodes); }
public Connector(NodeLink displayedLink, Pin?source, Pin?destination) { DisplayedLink = displayedLink; Source = source; Destination = destination; FillColor = DataCache.IconAverageColor(displayedLink.Item.Icon); }
public static NodeLink Create(ProductionNode supplier, ProductionNode consumer, Item item, float maxAmount = float.PositiveInfinity) { NodeLink link = new NodeLink(supplier, consumer, item, maxAmount); supplier.OutputLinks.Add(link); consumer.InputLinks.Add(link); supplier.Graph.InvalidateCaches(); return link; }
public static NodeLink Create(ProductionNode supplier, ProductionNode consumer, Item item, float maxAmount = float.PositiveInfinity) { NodeLink link = new NodeLink(supplier, consumer, item, maxAmount); supplier.OutputLinks.Add(link); consumer.InputLinks.Add(link); supplier.Graph.InvalidateCaches(); return(link); }
//Returns true if a new link was created public void CreateAllLinksForNode(ProductionNode node) { foreach (Item item in node.Inputs) { foreach (ProductionNode existingNode in Nodes.Where(n => n.Outputs.Contains(item))) { if (existingNode != node) { NodeLink.Create(existingNode, node, item); } } } }
public void LinkUpAllOutputs() { foreach (ProductionNode node in Nodes.ToList()) { foreach (Item item in node.Outputs) { // TODO: Write unit tests, figure out what to do about the GetExcessOutput check here // if (node.GetExcessOutput(item) > 0 || !node.OutputLinks.Any(l => l.Item == item)) if (!node.OutputLinks.Any(l => l.Item == item)) { if (Nodes.Any(n => n.Inputs.Contains(item) && (n.rateType == RateType.Auto) && !(n.InputLinks.Any(l => l.Supplier == node)))) { NodeLink.Create(node, Nodes.First(n => n.Inputs.Contains(item)), item); } else { var newNode = ConsumerNode.Create(item, this); newNode.rateType = RateType.Auto; NodeLink.Create(node, newNode, item); } } } } }
public static NodeLink?Create(ProductionNode supplier, ProductionNode consumer, Item item, float maxAmount = float.PositiveInfinity) { if (!supplier.Supplies(item) || !consumer.Consumes(item)) { throw new InvalidOperationException($"Cannot connect {supplier} to {consumer} using item {item}"); } if (consumer.InputLinks.Any(l => l.Item == item && l.Supplier == supplier)) { return(null); } if (supplier.OutputLinks.Any(l => l.Item == item && l.Consumer == consumer)) { return(null); } var link = new NodeLink(supplier, consumer, item, maxAmount); supplier.OutputLinks.Add(link); consumer.InputLinks.Add(link); supplier.Graph.InvalidateCaches(); return(link); }
public LinkElement(ProductionGraphViewer parent, NodeLink displayedLink) : base(parent) { DisplayedLink = displayedLink; }
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(); }
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 double Throughput(NodeLink link) { return(Links[link]); }
public void CreateSupplyNodeToSatisfyItemDemand(ProductionNode node, Item item) { SupplyNode newNode = SupplyNode.Create(item, node.Graph); NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item)); }
public void CreateRecipeNodeToSatisfyItemDemand(ProductionNode node, Item item, Recipe recipe) { RecipeNode newNode = RecipeNode.Create(recipe, this); NodeLink.Create(newNode, node, item, node.GetUnsatisfiedDemand(item)); }
private Variable variableFor(NodeLink inputLink, EndpointType type) { return(variableFor(Tuple.Create(inputLink, type), makeName("link", type, inputLink.Consumer.DisplayName, inputLink.Item.FriendlyName))); }