• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

samsmithnz / SatisfactoryTree / 17567158789

08 Sep 2025 11:39PM UTC coverage: 89.111% (+36.2%) from 52.88%
17567158789

Pull #284

github

web-flow
Merge 293d7617a into e771c4f78
Pull Request #284: Reworking logic to handle imports and exports

244 of 282 branches covered (86.52%)

Branch coverage included in aggregate %.

776 of 863 new or added lines in 25 files covered. (89.92%)

779 of 866 relevant lines covered (89.95%)

468.95 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.32
/src/SatisfactoryTree.Logic/Extraction/GameFileExtractor.cs
1
using SatisfactoryTree.Logic.Models;
2
using System.Diagnostics;
3
using System.Text.Json;
4

5
namespace SatisfactoryTree.Logic.Extraction
6
{
7
    public class GameFileExtractor
8
    {
9
        public string InputFile { get; set; } = "";
3✔
10
        public string OutputFile { get; set; } = "";
3✔
11

12
        public void GetContentFiles()
13
        {
1✔
14
            // Load the content file
15
            string contentPath = @"C:\Program Files (x86)\Steam\steamapps\common\Satisfactory\CommunityResources\Docs\en-US.json";
1✔
16
            DirectoryInfo? currentDir = new(Directory.GetCurrentDirectory());
1✔
17
            DirectoryInfo? parentDir = currentDir.Parent?.Parent?.Parent?.Parent?.Parent;
1!
18
            if (parentDir == null)
1!
NEW
19
            {
×
NEW
20
                throw new Exception("Parent directory structure is not as expected.");
×
21
            }
22
            string projectContentPath = Path.Combine(parentDir.FullName, "content");
1✔
23
            string projectContentFile = Path.Combine(projectContentPath, "en-US.json");
1✔
24

25
            // If the file exists, copy it to the content folder, that is located in the content folder in the root of the project
26
            if (File.Exists(contentPath) &&
1!
27
                Directory.Exists(projectContentPath))
1✔
NEW
28
            {
×
29
                //Get the current directory
NEW
30
                Debug.WriteLine("Copying file to " + projectContentPath);
×
NEW
31
                File.Copy(contentPath, projectContentFile, true);
×
NEW
32
            }
×
33
            InputFile = projectContentFile;
1✔
34
            OutputFile = Path.Combine(projectContentPath, "gameData.json");
1✔
35
        }
1✔
36

37
        public static async Task<ExtractedData> ProcessFileOldModel(string inputFile, string outputFile)
38
        {
1✔
39
            Stopwatch stopwatch = new();
1✔
40
            stopwatch.Start();
1✔
41
            //try
42
            //{
43
            //Read file contexts from text file
44
            string fileContent = File.ReadAllText(inputFile);
1✔
45
            List<dynamic>? rawData = System.Text.Json.JsonSerializer.Deserialize<List<dynamic>>(fileContent);
1✔
46
            List<JsonElement> data = new();
1✔
47
            List<JsonElement> rawResourcesData = new();
1✔
48
            if (rawData != null)
1✔
49
            {
1✔
50
                foreach (JsonElement entry in rawData)
227✔
51
                {
112✔
52
                    string? nativeClass = entry.TryGetProperty("NativeClass", out JsonElement nativeClassElement) ? nativeClassElement.GetString() : string.Empty;
112!
53
                    if (entry.TryGetProperty("Classes", out JsonElement classesElement) && classesElement.ValueKind == JsonValueKind.Array)
112!
54
                    {
112✔
55
                        data.AddRange(classesElement.EnumerateArray());
112✔
56
                    }
112✔
57
                }
112✔
58
            }
1✔
59

60
            // Get an array of all buildings that produce something
61
            List<string> producingBuildings = ProcessRawBuildings.GetProducingBuildings(data);
1✔
62

63
            // Get power consumption for the producing buildings
64
            Dictionary<string, double> buildings = ProcessRawBuildings.GetPowerConsumptionForBuildings(data, producingBuildings);
1✔
65

66
            // Pass the producing buildings with power data to getRecipes to calculate perMin and powerPerProduct
67
            List<Recipe> recipes = ProcessRawRecipes.GetProductionRecipes(data, buildings);
1✔
68

69
            // Get parts
70
            RawPartsAndRawMaterials items = ProcessRawParts.GetItems(data, recipes);
1✔
71
            ProcessRawParts.FixItemNames(items);
1✔
72
            ProcessRawParts.FixTurbofuel(items, recipes);
1✔
73

74
            // IMPORTANT: The order here matters - don't run this before fixing the turbofuel.
75
            List<PowerGenerationRecipe> powerGenerationRecipes = ProcessRawRecipes.GetPowerGeneratingRecipes(data, items, buildings);
1✔
76

77
            // Since we've done some manipulation of the items data, re-sort it
78
            Dictionary<string, Part> sortedItems = new();
1✔
79
            foreach (string? key in items.Parts.Keys.OrderBy(k => k))
507✔
80
            {
168✔
81
                sortedItems[key] = items.Parts[key];
168✔
82
            }
168✔
83
            items.Parts = sortedItems;
1✔
84

85
            //Build the new recipe collection
86
            List<Recipe> newRecipes = new();
1✔
87
            foreach (Recipe recipe in recipes)
585✔
88
            {
291✔
89
                newRecipes.Add(new()
291✔
90
                {
291✔
91
                    id = recipe.id,
291✔
92
                    displayName = recipe.displayName,
291✔
93
                    ingredients = recipe.ingredients,
291✔
94
                    products = recipe.products,
291✔
95
                    building = recipe.building,
291✔
96
                    isAlternate = recipe.isAlternate,
291✔
97
                    isFicsmas = recipe.isFicsmas,
291✔
98
                    usesSAMOre = recipe.usesSAMOre
291✔
99
                });
291✔
100
            }
291✔
101
            //Now add the power generation recipes
102
            foreach (PowerGenerationRecipe recipe in powerGenerationRecipes)
37✔
103
            {
17✔
104
                List<Ingredient> ingredients = new();
17✔
105
                foreach (PowerIngredient ingredient in recipe.ingredients)
97✔
106
                {
23✔
107
                    ingredients.Add(new Ingredient()
23✔
108
                    {
23✔
109
                        part = ingredient.part,
23✔
110
                        amount = ingredient.perMin,
23✔
111
                        perMin = ingredient.perMin,
23✔
112
                        mwPerItem = ingredient.mwPerItem,
23✔
113
                    });
23✔
114
                }
23✔
115
                List<Product> products = new();
17✔
116
                if (recipe.byproduct != null)
17✔
117
                {
2✔
118
                    products.Add(
2✔
119
                        new Product()
2✔
120
                        {
2✔
121
                            part = recipe.byproduct.part,
2✔
122
                            amount = recipe.byproduct.perMin,
2✔
123
                            perMin = recipe.byproduct.perMin,
2✔
124
                            isByProduct = true
2✔
125
                        }
2✔
126
                    );
2✔
127
                }
2✔
128

129
                // Check if any ingredient is SAMIngot to set usesSAMOre flag
130
                bool usesSAMOre = ingredients.Any(ingredient => ingredient.part == "SAMIngot");
40✔
131

132
                newRecipes.Add(new()
17✔
133
                {
17✔
134
                    id = recipe.id,
17✔
135
                    displayName = recipe.displayName,
17✔
136
                    ingredients = ingredients,
17✔
137
                    products = products,
17✔
138
                    building = recipe.building,
17✔
139
                    isAlternate = false,
17✔
140
                    isFicsmas = false,
17✔
141
                    usesSAMOre = usesSAMOre
17✔
142
                });
17✔
143
            }
17✔
144
            //sort the new recipes list by id
145
            newRecipes = newRecipes.OrderBy(r => r.id).ToList();
309✔
146

147
            // Construct the final JSON object
148
            ExtractedData finalData = new(
1✔
149
                buildings,
1✔
150
                items,
1✔
151
                recipes,
1✔
152
                powerGenerationRecipes);
1✔
153

154
            // Write the output to the file
155
            JsonSerializerOptions options = new() { WriteIndented = true, DefaultIgnoreCondition = System.Text.Json.Serialization.JsonIgnoreCondition.WhenWritingNull };
1✔
156
            string outputJson = System.Text.Json.JsonSerializer.Serialize(finalData, options);
1✔
157
            await File.WriteAllTextAsync(outputFile, outputJson);
1✔
158
            stopwatch.Stop();
1✔
159

160
            System.Console.WriteLine($"Processed {items.Parts.Count} parts, {buildings.Count} buildings, and {recipes.Count} recipes, all written to {outputFile}.");
1✔
161
            System.Console.WriteLine($"Total processing time: {stopwatch.Elapsed.TotalMilliseconds} ms");
1✔
162
            return finalData;
1✔
163
            //}
164
            //catch (Exception ex)
165
            //{
166
            //    System.Console.Error.WriteLine($"Error processing file: {ex.Message}");
167
            //    return null;
168
            //}
169
        }
1✔
170
    }
171
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc