Skip to content

Commit

Permalink
Fix #363 Exception in automation analysis (#364)
Browse files Browse the repository at this point in the history
Fixes #363 by generating a correct dependency tree. Also adds an
exception earlier in the process when generating invalid node.
  • Loading branch information
shpaass authored Nov 22, 2024
2 parents df92acb + 48bd6ab commit a56f195
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 9 deletions.
12 changes: 10 additions & 2 deletions Yafc.Model/Analysis/DependencyNode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,10 @@ internal static DependencyNode Create(IEnumerable<DependencyNode> dependencies)
}
realDependencies = realDependencies.Distinct().ToList();

if (realDependencies.Count == 0) {
throw new ArgumentException($"Must not join zero nodes with an 'and'. Instead, create an empty DependencyList to explain what expected dependencies are missing.");
}

// Prevent single-child nodes, so the drawing and preceding unpacking code doesn't have to handle that.
if (realDependencies.Count == 1) {
return realDependencies[0];
Expand Down Expand Up @@ -175,6 +179,10 @@ internal static DependencyNode Create(IEnumerable<DependencyNode> dependencies)
}
realDependencies = realDependencies.Distinct().ToList();

if (realDependencies.Count == 0) {
throw new ArgumentException($"Must not join zero nodes with an 'or'. Instead, create an empty DependencyList to explain what expected dependencies are missing.");
}

// Prevent single-child nodes, so the drawing and preceding unpacking code doesn't have to handle that.
if (realDependencies.Count == 1) {
return realDependencies[0];
Expand All @@ -186,7 +194,7 @@ internal static DependencyNode Create(IEnumerable<DependencyNode> dependencies)
internal override IEnumerable<FactorioId> Flatten() => dependencies.SelectMany(d => d.Flatten());

internal override bool IsAccessible(Func<FactorioId, bool> isAccessible) => dependencies.Any(d => d.IsAccessible(isAccessible));
internal override Bits AggregateBits(Func<FactorioId, Bits> getBits) => dependencies.Select(d => d.AggregateBits(getBits)).Min();
internal override Bits AggregateBits(Func<FactorioId, Bits> getBits) => dependencies.Min(d => d.AggregateBits(getBits));
internal override AutomationStatus IsAutomatable(Func<FactorioId, AutomationStatus> isAutomatable, AutomationStatus automationState)
=> dependencies.Max(d => d.IsAutomatable(isAutomatable, automationState));

Expand Down Expand Up @@ -234,7 +242,7 @@ internal override Bits AggregateBits(Func<FactorioId, Bits> getBits) {
return bits;
}
else if (dependencies.elements.Length > 0) {
return bits | dependencies.elements.Select(getBits).Min();
return bits | dependencies.elements.Min(getBits);
}
return bits;
}
Expand Down
27 changes: 20 additions & 7 deletions Yafc.Model/Data/DataClasses.cs
Original file line number Diff line number Diff line change
Expand Up @@ -540,24 +540,32 @@ public float Power(Quality quality)
internal Lazy<Entity?>? getSpoilResult;

public sealed override DependencyNode GetDependencies() {
List<DependencyList> collector = [];
List<DependencyNode> collector = [];
if (energy != null) {
collector.Add(new(energy.fuels, DependencyList.Flags.Fuel));
collector.Add(new DependencyList(energy.fuels, DependencyList.Flags.Fuel));
}
if (spawnLocations.Length != 0) {
collector.Add(new(spawnLocations, DependencyList.Flags.Location));
if (mapGenerated) {
if (itemsToPlace.Length != 0) {
collector.Add(DependencyNode.RequireAny(
new DependencyList(spawnLocations, DependencyList.Flags.Location),
new DependencyList(itemsToPlace, DependencyList.Flags.ItemToPlace)));
}
else {
collector.Add(new DependencyList(spawnLocations, DependencyList.Flags.Location));
}
}

if (sourceEntities.Count > 0) {
// Asteroid chunks require locations OR bigger-asteroid
collector.Add(new(sourceEntities, DependencyList.Flags.Source));
collector.Add(new DependencyList(sourceEntities, DependencyList.Flags.Source));
return DependencyNode.RequireAny(collector);
}

if (captureAmmo.Count == 0) {
if (!mapGenerated) {
collector.Add(new(itemsToPlace, DependencyList.Flags.ItemToPlace));
collector.Add(new DependencyList(itemsToPlace, DependencyList.Flags.ItemToPlace));
}

return DependencyNode.RequireAll(collector);
}

Expand Down Expand Up @@ -600,7 +608,12 @@ public sealed override DependencyNode GetDependencies() {
nonFuel.Add(DependencyNode.Create(new(Array.Empty<FactorioId>(), DependencyList.Flags.Source)));
}

return DependencyNode.RequireAll(DependencyNode.Create(collector[0]), DependencyNode.RequireAny(nonFuel));
if (energy != null) {
return DependencyNode.RequireAll(collector[0] /* fuel */, DependencyNode.RequireAny(nonFuel));
}
else { // Doesn't require fuel
return DependencyNode.RequireAny(nonFuel);
}
}

private sealed class ListComparer : IEqualityComparer<List<EntitySpawner>> {
Expand Down
5 changes: 5 additions & 0 deletions changelog.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,11 @@
// Internal changes:
// Changes to the code that do not affect the behavior of the program.
----------------------------------------------------------------------------------------------------------------------
Version:
Date:
Fixes:
- "Map generated" entities that don't generate in any locations could break automation analysis.
----------------------------------------------------------------------------------------------------------------------
Version: 2.4.0
Date: November 21st 2024
Features:
Expand Down

0 comments on commit a56f195

Please sign in to comment.