diff --git a/Yafc.Model/Data/DataClasses.cs b/Yafc.Model/Data/DataClasses.cs index cb55c012..ab7dcb03 100644 --- a/Yafc.Model/Data/DataClasses.cs +++ b/Yafc.Model/Data/DataClasses.cs @@ -490,6 +490,9 @@ public enum AllowedEffects { } public class Tile : FactorioObject { + // Tiles participate in accessibility analysis, but only until the pumping recipes get around to reading the locations where their tiles + // appear. They often don't have an icon, and don't participate in anything else Yafc cares about, so hide them. + public Tile() => showInExplorers = false; public Fluid? Fluid { get; internal set; } internal override FactorioObjectSortOrder sortingOrder => FactorioObjectSortOrder.Tiles; diff --git a/Yafc.Parser/Data/FactorioDataDeserializer.cs b/Yafc.Parser/Data/FactorioDataDeserializer.cs index 8b92006d..2ca2d218 100644 --- a/Yafc.Parser/Data/FactorioDataDeserializer.cs +++ b/Yafc.Parser/Data/FactorioDataDeserializer.cs @@ -380,9 +380,8 @@ private static EffectReceiver ParseEffectReceiver(LuaTable? table) { } private void DeserializeItem(LuaTable table, ErrorCollector _1) { - string name = table.Get("name", ""); if (table.Get("type", "") == "module" && table.Get("effect", out LuaTable? moduleEffect)) { - Module module = GetObject(name); + Module module = GetObject(table); var effect = ParseEffect(moduleEffect); module.moduleSpecification = new ModuleSpecification { category = table.Get("category", ""), @@ -394,7 +393,7 @@ private void DeserializeItem(LuaTable table, ErrorCollector _1) { }; } else if (table.Get("type", "") == "ammo" && table["ammo_type"] is LuaTable ammo_type) { - Ammo ammo = GetObject(name); + Ammo ammo = GetObject(table); ammo_type.ReadObjectOrArray(readAmmoType); if (ammo_type["target_filter"] is LuaTable targets) { @@ -556,13 +555,13 @@ private void DeserializeFluid(LuaTable table, ErrorCollector _) { private Goods? LoadItemOrFluid(LuaTable table, bool useTemperature) { if (table.Get("type", out string? type) && table.Get("name", out string? name)) { if (type == "item") { - return GetObject(name); + return GetObject(table); } else if (type == "fluid") { if (useTemperature && table.Get("temperature", out int temperature)) { return GetFluidFixedTemp(name, temperature); } - return GetObject(name); + return GetObject(table); } } @@ -599,7 +598,7 @@ private void DeserializeLocation(LuaTable table, ErrorCollector collector) { throw new NotSupportedException($"Read a definition of a {prototypeType} that does not have a name."); } - var target = GetObject(name); + var target = GetObject(table); target.factorioType = table.Get("type", ""); if (table.Get("localised_name", out object? loc)) { // Keep UK spelling for Factorio/LUA data objects diff --git a/Yafc.Parser/Data/FactorioDataDeserializer_Context.cs b/Yafc.Parser/Data/FactorioDataDeserializer_Context.cs index 5bbbd585..49b4a859 100644 --- a/Yafc.Parser/Data/FactorioDataDeserializer_Context.cs +++ b/Yafc.Parser/Data/FactorioDataDeserializer_Context.cs @@ -108,8 +108,54 @@ Item createSpecialItem(string name, string locName, string locDescr, string icon totalItemOutput = createSpecialItem("item-total-output", "Total item production", "This item represents the combined total item output of a multi-product recipe. It can be used to set or measure the number of sushi belts required to handle the products of this recipe row.", "__base__/graphics/icons/signal/signal_O.png"); } + /// + /// Calls , with both type parameters set to . + /// + private T GetObject(LuaTable table) where T : FactorioObject, new() => GetObject(table); + + /// + /// Gets or creates an object with the specified nominal and actual types, based on the supplied . If + /// describes a blueprint parameter, the returned object will not be shown in NEIE, Dependency Explorer, or + /// Desired Product windows. + /// + /// The nominal type. In general, this is the most-derived type such that all possible callers will know the + /// object is of this type, and the least-derived type such that (typeof(), + /// ["name"]) is unique across all objects. + /// The concrete type of the object. This can be either same as , or a type derived + /// from it. If the object already exists, it must have been created as an object of this type (or a derived type). + /// The to read when to get the object's name. This table must have a name key. If the + /// value of its parameter key is , and + /// , if applicable, will be set to . + /// The new or pre-existing object described by and ["name"]. + private TActual GetObject(LuaTable table) where TNominal : FactorioObject where TActual : TNominal, new() { + if (!table.Get("name", out string? name)) { + throw new ArgumentException($"{nameof(table)} must contain a 'name' key. Call GetObject(string) instead.", nameof(table)); + } + TActual result = GetObject(name); + if (table.Get("parameter", false)) { + result.showInExplorers = false; + if (result is Goods goods) { + goods.isLinkable = false; + } + } + return result; + } + + /// + /// Calls , with both type parameters set to . + /// private T GetObject(string name) where T : FactorioObject, new() => GetObject(name); + /// + /// Gets or creates an object with the specified nominal and actual types, with the supplied name. + /// + /// The nominal type. In general, this is the most-derived type such that all possible callers will know the + /// object is of this type, and the least-derived type such that (typeof(), + /// ) is unique across all objects. + /// The concrete type of the object. This can be either same as , or a type derived + /// from it. If the object already exists, it must have been created as an object of this type (or a derived type). + /// The name of the object to get or create. + /// The new or pre-existing object described by and . private TActual GetObject(string name) where TNominal : FactorioObject where TActual : TNominal, new() { var key = (typeof(TNominal), name); if (registeredObjects.TryGetValue(key, out FactorioObject? existing)) { diff --git a/Yafc.Parser/Data/FactorioDataDeserializer_Entity.cs b/Yafc.Parser/Data/FactorioDataDeserializer_Entity.cs index 47772404..391c883b 100644 --- a/Yafc.Parser/Data/FactorioDataDeserializer_Entity.cs +++ b/Yafc.Parser/Data/FactorioDataDeserializer_Entity.cs @@ -176,14 +176,14 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { // case "furnace": // case "rocket-silo": // Out of order case "accumulator": - var accumulator = GetObject(name); + var accumulator = GetObject(table); if (table.Get("energy_source", out LuaTable? accumulatorEnergy) && accumulatorEnergy.Get("buffer_capacity", out string? capacity)) { accumulator.baseAccumulatorCapacity = ParseEnergy(capacity); } break; case "agricultural-tower": - var agriculturalTower = GetObject(name); + var agriculturalTower = GetObject(table); _ = table.Get("energy_usage", out usesPower); agriculturalTower.basePower = ParseEnergy(usesPower); float radius = table.Get("radius", 1f); @@ -194,7 +194,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { case "assembling-machine": goto case "furnace"; case "asteroid": - Entity asteroid = GetObject(name); + Entity asteroid = GetObject(table); if (table.Get("dying_trigger_effect", out LuaTable? death)) { death.ReadObjectOrArray(trigger => { switch (trigger.Get("type")) { @@ -207,7 +207,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "asteroid-collector": - EntityCrafter collector = GetObject(name); + EntityCrafter collector = GetObject(table); _ = table.Get("arm_energy_usage", out usesPower); collector.basePower = ParseEnergy(usesPower) * 60; _ = table.Get("passive_energy_usage", out usesPower); @@ -216,7 +216,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { recipeCrafters.Add(collector, SpecialNames.AsteroidCapture); break; case "beacon": - var beacon = GetObject(name); + var beacon = GetObject(table); beacon.baseBeaconEfficiency = table.Get("distribution_effectivity", 0f); beacon.profile = table.Get("profile", out LuaTable? profile) ? profile.ArrayElements().Select(x => (float)x).ToArray() : [1f]; _ = table.Get("energy_usage", out usesPower); @@ -224,7 +224,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { beacon.basePower = ParseEnergy(usesPower); break; case "boiler": - var boiler = GetObject(name); + var boiler = GetObject(table); _ = table.Get("energy_consumption", out usesPower); boiler.basePower = ParseEnergy(usesPower); boiler.fluidInputs = 1; @@ -251,7 +251,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { boiler.baseCraftingSpeed = 1f; break; case "burner-generator": - var generator = GetObject(name); + var generator = GetObject(table); // generator energy input config is strange if (table.Get("max_power_output", out string? maxPowerOutput)) { @@ -269,7 +269,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { recipeCrafters.Add(generator, SpecialNames.GeneratorRecipe); break; case "character": - var character = GetObject(name); + var character = GetObject(table); character.itemInputs = 255; if (table.Get("mining_categories", out LuaTable? resourceCategories)) { @@ -300,7 +300,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "container": - var container = GetObject(name); + var container = GetObject(table); container.inventorySize = table.Get("inventory_size", 0); if (factorioType == "logistic-container") { @@ -312,7 +312,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "electric-energy-interface": - var eei = GetObject(name); + var eei = GetObject(table); eei.energy = voidEntityEnergy; if (table.Get("energy_production", out string? interfaceProduction)) { @@ -323,7 +323,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "furnace": - var crafter = GetObject(name); + var crafter = GetObject(table); _ = table.Get("energy_usage", out usesPower); ParseModules(table, crafter, AllowedEffects.None); crafter.basePower = ParseEnergy(usesPower); @@ -380,12 +380,12 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { case "generator": goto case "burner-generator"; case "inserter": - var inserter = GetObject(name); + var inserter = GetObject(table); inserter.inserterSwingTime = 1f / (table.Get("rotation_speed", 1f) * 60); inserter.isBulkInserter = table.Get("bulk", false); break; case "lab": - var lab = GetObject(name); + var lab = GetObject(table); _ = table.Get("energy_usage", out usesPower); ParseModules(table, lab, AllowedEffects.All ^ AllowedEffects.Quality); lab.basePower = ParseEnergy(usesPower); @@ -399,7 +399,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { case "logistic-container": goto case "container"; case "mining-drill": - var drill = GetObject(name); + var drill = GetObject(table); _ = table.Get("energy_usage", out usesPower); drill.basePower = ParseEnergy(usesPower); ParseModules(table, drill, AllowedEffects.All); @@ -418,7 +418,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "offshore-pump": - var pump = GetObject(name); + var pump = GetObject(table); _ = table.Get("energy_usage", out usesPower); pump.basePower = ParseEnergy(usesPower); pump.baseCraftingSpeed = table.Get("pumping_speed", 20f) / 20f; @@ -443,7 +443,7 @@ private void DeserializeEntity(LuaTable table, ErrorCollector errorCollector) { } break; case "projectile": - var projectile = GetObject(name); + var projectile = GetObject(table); if (table["action"] is LuaTable actions) { actions.ReadObjectOrArray(parseAction); } @@ -465,7 +465,7 @@ void parseEffect(LuaTable effect) { } break; case "reactor": - var reactor = GetObject(name); + var reactor = GetObject(table); reactor.reactorNeighborBonus = table.Get("neighbour_bonus", 1f); // Keep UK spelling for Factorio/LUA data objects _ = table.Get("consumption", out usesPower); reactor.basePower = ParseEnergy(usesPower); @@ -475,17 +475,17 @@ void parseEffect(LuaTable effect) { case "rocket-silo": goto case "furnace"; case "solar-panel": - var solarPanel = GetObject(name); + var solarPanel = GetObject(table); solarPanel.energy = voidEntityEnergy; _ = table.Get("production", out string? powerProduction); recipeCrafters.Add(solarPanel, SpecialNames.GeneratorRecipe); solarPanel.baseCraftingSpeed = ParseEnergy(powerProduction) * 0.7f; // 0.7f is a solar panel ratio on nauvis break; case "transport-belt": - GetObject(name).beltItemsPerSecond = table.Get("speed", 0f) * 480f; + GetObject(table).beltItemsPerSecond = table.Get("speed", 0f) * 480f; break; case "unit-spawner": - var spawner = GetObject(name); + var spawner = GetObject(table); spawner.capturedEntityName = table.Get("captured_spawner_entity"); break; } @@ -602,11 +602,13 @@ void readDeathEffect(LuaTable effect) { private void DeserializeAsteroidChunk(LuaTable table, ErrorCollector errorCollector) { Entity chunk = DeserializeCommon(table, "asteroid-chunk"); Item asteroid = GetObject(chunk.name); - Recipe recipe = CreateSpecialRecipe(asteroid, SpecialNames.AsteroidCapture, "mining"); - recipe.time = 1; - recipe.ingredients = []; - recipe.products = [new Product(asteroid, 1)]; - recipe.sourceEntity = chunk; + if (asteroid.showInExplorers) { // don't create mining recipes for parameter chunks. + Recipe recipe = CreateSpecialRecipe(asteroid, SpecialNames.AsteroidCapture, "mining"); + recipe.time = 1; + recipe.ingredients = []; + recipe.products = [new Product(asteroid, 1)]; + recipe.sourceEntity = chunk; + } } private float EstimateArgument(LuaTable args, string name, float def = 0) => args.Get(name, out LuaTable? res) ? EstimateNoiseExpression(res) : def; diff --git a/Yafc/Windows/MilestonesEditor.cs b/Yafc/Windows/MilestonesEditor.cs index fea246c1..4485cca6 100644 --- a/Yafc/Windows/MilestonesEditor.cs +++ b/Yafc/Windows/MilestonesEditor.cs @@ -63,7 +63,7 @@ public override void Build(ImGui gui) { milestoneList.RebuildContents(); } if (gui.BuildButton("Add milestone")) { - SelectMultiObjectPanel.Select(Database.objects.all.Except(Project.current.settings.milestones), "Add new milestone", AddMilestone); + SelectMultiObjectPanel.Select(Database.objects.explorable.Except(Project.current.settings.milestones), "Add new milestone", AddMilestone); } } } diff --git a/Yafc/Windows/NeverEnoughItemsPanel.cs b/Yafc/Windows/NeverEnoughItemsPanel.cs index 9d75f58a..e758601b 100644 --- a/Yafc/Windows/NeverEnoughItemsPanel.cs +++ b/Yafc/Windows/NeverEnoughItemsPanel.cs @@ -356,7 +356,7 @@ public override void Build(ImGui gui) { } if (gui.BuildFactorioObjectButtonBackground(gui.lastRect, current, SchemeColor.Grey) == Click.Left) { - SelectSingleObjectPanel.Select(Database.goods.all, "Select item", SetItem); + SelectSingleObjectPanel.Select(Database.goods.explorable, "Select item", SetItem); } using (var split = gui.EnterHorizontalSplit(2)) { diff --git a/Yafc/Workspace/AutoPlannerView.cs b/Yafc/Workspace/AutoPlannerView.cs index be2302c7..64fd0f7c 100644 --- a/Yafc/Workspace/AutoPlannerView.cs +++ b/Yafc/Workspace/AutoPlannerView.cs @@ -50,7 +50,7 @@ void page1(ImGui gui, ref bool valid) { } grid.Next(); if (gui.BuildButton(Icon.Plus, SchemeColor.Primary, SchemeColor.PrimaryAlt, size: 2.5f)) { - SelectSingleObjectPanel.Select(Database.goods.all, "New production goal", x => { + SelectSingleObjectPanel.Select(Database.goods.explorable, "New production goal", x => { goal.Add(new AutoPlannerGoal { amount = 1f, item = x }); gui.Rebuild(); }); diff --git a/Yafc/Workspace/ProductionTable/ProductionTableView.cs b/Yafc/Workspace/ProductionTable/ProductionTableView.cs index 8b00031a..2ee06a8f 100644 --- a/Yafc/Workspace/ProductionTable/ProductionTableView.cs +++ b/Yafc/Workspace/ProductionTable/ProductionTableView.cs @@ -259,7 +259,7 @@ private static void BuildRecipeButton(ImGui gui, ProductionTable table) { r => table.AddRecipe(r, DefaultVariantOrdering), checkMark: r => table.recipes.Any(rr => rr.recipe == r)); } else { - SelectMultiObjectPanel.Select(Database.recipes.all, "Select raw recipe", + SelectMultiObjectPanel.Select(Database.recipes.explorable, "Select raw recipe", r => table.AddRecipe(r, DefaultVariantOrdering), checkMark: r => table.recipes.Any(rr => rr.recipe == r)); } } diff --git a/changelog.txt b/changelog.txt index ceb8643b..b56a9918 100644 --- a/changelog.txt +++ b/changelog.txt @@ -22,6 +22,9 @@ Date: - (SA) Locations (except nauvis) are now part of the default milestone list. - Milestone overlays can be displayed on inaccessible objects. - With 22+ milestones, tooltip headers don't draw them unnecessarily overlapped, and can use multiple lines. + Fixes: + - Hide blueprint parameters and tiles from the Dependency Explorer and NEIE. + - Hide blueprint parameters and the synthetic I and O items from more selection windows. Internal changes: - Dependency and automation analysis allows more ORs, e.g. "(spawner and capture-ammo) or item-to-place". ----------------------------------------------------------------------------------------------------------------------