Skip to content

Commit

Permalink
Add fuel consumption recipe for products (#109)
Browse files Browse the repository at this point in the history
Fixes #76

This adds the option for products that are usable as fuel, to select a
recipe based on that fuel consumption. YaFC will then attempt to add
said recipe using the selected fuel.

I had to do some performance optimization since the electric power, or
biomass, tends to select most py recipes (!), i saw over 8000 of them in
my debugger. It now pre-sorts the list when the popup is opened, not
each time you move the mouse over.

![example](https://github.com/have-fun-was-taken/yafc-ce/assets/4461459/4c7653c4-4711-4e1f-bead-1abeba96403d)
  • Loading branch information
shpaass authored May 10, 2024
2 parents 5f88b1d + 03632fc commit 3e55845
Show file tree
Hide file tree
Showing 7 changed files with 40 additions and 17 deletions.
6 changes: 6 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,19 @@ dotnet_style_prefer_conditional_expression_over_return = false:none
###############################
# Style Definitions
dotnet_naming_style.pascal_case_style.capitalization = pascal_case
dotnet_naming_style.camel_case_style.capitalization = camel_case
# Use PascalCase for constant fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.severity = suggestion
dotnet_naming_rule.constant_fields_should_be_pascal_case.symbols = constant_fields
dotnet_naming_rule.constant_fields_should_be_pascal_case.style = pascal_case_style
dotnet_naming_symbols.constant_fields.applicable_kinds = field
dotnet_naming_symbols.constant_fields.applicable_accessibilities = *
dotnet_naming_symbols.constant_fields.required_modifiers = const
# Use camcel case for local variable
dotnet_naming_rule.use_camel_case_rule.symbols = use_camel_case
dotnet_naming_rule.use_camel_case_rule.style = camel_case_style
dotnet_naming_rule.use_camel_case_rule.severity = suggestion
dotnet_naming_symbols.use_camel_case.applicable_kinds = parameter,local,local_function
###############################
# C# Coding Conventions #
###############################
Expand Down
1 change: 1 addition & 0 deletions Yafc.Model/Data/DataUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public static class DataUtils {
return x.RecipeWaste().CompareTo(y.RecipeWaste());
});
public static readonly FactorioObjectComparer<Recipe> AlreadySortedRecipe = new FactorioObjectComparer<Recipe>(DefaultRecipeOrdering.Compare);
public static readonly FactorioObjectComparer<EntityCrafter> CrafterOrdering = new FactorioObjectComparer<EntityCrafter>((x, y) => {
if (x.energy.type != y.energy.type) {
return x.energy.type.CompareTo(y.energy.type);
Expand Down
1 change: 1 addition & 0 deletions Yafc.UI/Rendering/Font.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ namespace Yafc.UI {
public class Font {
public static Font header;
public static Font subheader;
public static Font productionTableHeader;
public static Font text;

public readonly float size;
Expand Down
1 change: 1 addition & 0 deletions Yafc/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ private static void Main(string[] args) {
Font.header = new Font(overriddenFontFile ?? new FontFile("Data/Roboto-Light.ttf"), 2f);
var regular = overriddenFontFile ?? new FontFile("Data/Roboto-Regular.ttf");
Font.subheader = new Font(regular, 1.5f);
Font.productionTableHeader = new Font(regular, 1.23f);
Font.text = new Font(regular, 1f);

ProjectDefinition cliProject = CommandLineParser.Parse(args);
Expand Down
23 changes: 10 additions & 13 deletions Yafc/Widgets/ImmediateWidgets.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using SDL2;
using Yafc.Model;
Expand Down Expand Up @@ -114,16 +115,16 @@ public static bool BuildFactorioObjectButtonWithText(this ImGui gui, FactorioObj

public static bool BuildInlineObjectList<T>(this ImGui gui, IEnumerable<T> list, IComparer<T> ordering, string header, out T selected, int maxCount = 10,
Predicate<T> checkMark = null, Func<T, string> extra = null) where T : FactorioObject {
gui.BuildText(header, Font.subheader);
List<T> sortedList = new List<T>(list);
sortedList.Sort(ordering ?? DataUtils.DefaultOrdering);
gui.BuildText(header, Font.productionTableHeader);
IEnumerable<T> sortedList;
if (ordering == DataUtils.AlreadySortedRecipe) {
sortedList = list.AsEnumerable();
}
else {
sortedList = list.OrderBy(e => e, ordering ?? DataUtils.DefaultOrdering);
}
selected = null;
int count = 0;
foreach (var elem in sortedList) {
if (count++ >= maxCount) {
break;
}

foreach (var elem in sortedList.Take(maxCount)) {
string extraText = extra?.Invoke(elem);
if (gui.BuildFactorioObjectButtonWithText(elem, extraText)) {
selected = elem;
Expand Down Expand Up @@ -157,10 +158,6 @@ public static void BuildInlineObjectListAndButton<T>(this ImGui gui, ICollection
SelectSingleObjectPanel.Select(list, header, select, ordering, allowNone);
}
}

if (multiple && list.Count > 1) {
gui.BuildText("Hint: ctrl+click to add multiple", wrap: true, color: SchemeColor.BackgroundTextFaint);
}
}
}

Expand Down
24 changes: 20 additions & 4 deletions Yafc/Workspace/ProductionTable/ProductionTableView.cs
Original file line number Diff line number Diff line change
Expand Up @@ -595,12 +595,13 @@ public override void CreateModelDropdown(ImGui gui, Type type, Project project)
}

private static readonly IComparer<Goods> DefaultVariantOrdering = new DataUtils.FactorioObjectComparer<Goods>((x, y) => (y.ApproximateFlow() / MathF.Abs(y.Cost())).CompareTo(x.ApproximateFlow() / MathF.Abs(x.Cost())));
private RecipeRow AddRecipe(ProductionTable table, Recipe recipe) {
private RecipeRow AddRecipe(ProductionTable table, Recipe recipe, Goods selectedFuel = null) {
RecipeRow recipeRow = new RecipeRow(table, recipe);
table.RecordUndo().recipes.Add(recipeRow);
recipeRow.entity = recipe.crafters.AutoSelect(DataUtils.FavoriteCrafter);
EntityCrafter selectedFuelCrafter = selectedFuel?.fuelFor.OfType<EntityCrafter>().Where(e => e.recipes.OfType<Recipe>().Any(e => e == recipe)).AutoSelect(DataUtils.FavoriteCrafter);
recipeRow.entity = selectedFuelCrafter ?? recipe.crafters.AutoSelect(DataUtils.FavoriteCrafter);
if (recipeRow.entity != null) {
recipeRow.fuel = recipeRow.entity.energy.fuels.AutoSelect(DataUtils.FavoriteFuel);
recipeRow.fuel = recipeRow.entity.energy.fuels.FirstOrDefault(e => e == selectedFuel) ?? recipeRow.entity.energy.fuels.AutoSelect(DataUtils.FavoriteFuel);
}

foreach (var ingr in recipeRow.recipe.ingredients) {
Expand Down Expand Up @@ -657,6 +658,7 @@ bool recipeExists(Recipe rec) {
return allRecipes.Contains(rec);
}

Goods selectedFuel = null;
async void addRecipe(Recipe rec) {
if (variants == null) {
CreateLink(context, goods);
Expand All @@ -674,7 +676,7 @@ async void addRecipe(Recipe rec) {
}
}
if (!allRecipes.Contains(rec) || (await MessageBox.Show("Recipe already exists", $"Add a second copy of {rec.locName}?", "Add a copy", "Cancel")).choice) {
_ = AddRecipe(context, rec);
_ = AddRecipe(context, rec, selectedFuel);
}
}

Expand All @@ -692,6 +694,7 @@ async void addRecipe(Recipe rec) {
recipe.RecordUndo().fuel = fuel;
});
var allProduction = goods == null ? Array.Empty<Recipe>() : variants == null ? goods.production : variants.SelectMany(x => x.production).Distinct().ToArray();
Recipe[] fuelUseList = goods?.fuelFor.AsEnumerable().OfType<EntityCrafter>().SelectMany(e => e.recipes).OfType<Recipe>().Distinct().OrderBy(e => e, DataUtils.DefaultRecipeOrdering).ToArray() ?? [];
var fuelDisplayFunc = recipe?.entity?.energy.type == EntityEnergyType.FluidHeat
? (Func<Goods, string>)(g => DataUtils.FormatAmount(g.fluid?.heatValue ?? 0, UnitOfMeasure.Megajoule))
: g => DataUtils.FormatAmount(g.fuelValue, UnitOfMeasure.Megajoule);
Expand Down Expand Up @@ -753,8 +756,10 @@ void DropDownContent(ImGui gui) {
}
}

int numberOfShownRecipes = 0;
if (type != ProductDropdownType.Product && goods != null && allProduction.Length > 0) {
gui.BuildInlineObjectListAndButton(allProduction, comparer, addRecipe, "Add production recipe", 6, true, recipeExists);
numberOfShownRecipes += allProduction.Length;
if (link == null) {
Rect iconRect = new Rect(gui.lastRect.Right - 2f, gui.lastRect.Top, 2f, 2f);
gui.DrawIcon(iconRect.Expand(-0.2f), Icon.OpenNew, gui.textColor);
Expand All @@ -770,10 +775,21 @@ void DropDownContent(ImGui gui) {

if (type != ProductDropdownType.Fuel && goods != null && type != ProductDropdownType.Ingredient && goods.usages.Length > 0) {
gui.BuildInlineObjectListAndButton(goods.usages, DataUtils.DefaultRecipeOrdering, addRecipe, "Add consumption recipe", type == ProductDropdownType.Product ? 6 : 3, true, recipeExists);
numberOfShownRecipes += goods.usages.Length;
}

if (type != ProductDropdownType.Fuel && goods != null && type != ProductDropdownType.Ingredient && fuelUseList.Length > 0) {
gui.BuildInlineObjectListAndButton(fuelUseList, DataUtils.AlreadySortedRecipe, (x) => { selectedFuel = goods; addRecipe(x); }, "Add fuel usage", type == ProductDropdownType.Product ? 6 : 3, true, recipeExists);
numberOfShownRecipes += fuelUseList.Length;
}

if (type == ProductDropdownType.Product && goods != null && allProduction.Length > 0) {
gui.BuildInlineObjectListAndButton(allProduction, comparer, addRecipe, "Add production recipe", 1, true, recipeExists);
numberOfShownRecipes += allProduction.Length;
}

if (numberOfShownRecipes > 1) {
gui.BuildText("Hint: ctrl+click to add multiple", wrap: true, color: SchemeColor.BackgroundTextFaint);
}

if (link != null && gui.BuildCheckBox("Allow overproduction", link.algorithm == LinkAlgorithm.AllowOverProduction, out bool newValue)) {
Expand Down
1 change: 1 addition & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ Version: 0.6.5
Date: soon
Changes:
- Add a help message and proper handling for command line arguments
- Add fuel consumption recipe for products
----------------------------------------------------------------------------------------------------------------------
Version: 0.6.4
Date: April 16th 2024
Expand Down

0 comments on commit 3e55845

Please sign in to comment.