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

samsmithnz / SatisfactoryTree / 17569747743

09 Sep 2025 02:18AM UTC coverage: 89.817% (+36.9%) from 52.88%
17569747743

Pull #284

github

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

274 of 314 branches covered (87.26%)

Branch coverage included in aggregate %.

855 of 943 new or added lines in 26 files covered. (90.67%)

855 of 943 relevant lines covered (90.67%)

1804.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; } = "";
12✔
10
        public string OutputFile { get; set; } = "";
12✔
11

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

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

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

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

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

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

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

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

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

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

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

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

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

160
            System.Console.WriteLine($"Processed {items.Parts.Count} parts, {buildings.Count} buildings, and {recipes.Count} recipes, all written to {outputFile}.");
4✔
161
            System.Console.WriteLine($"Total processing time: {stopwatch.Elapsed.TotalMilliseconds} ms");
4✔
162
            return finalData;
4✔
163
            //}
164
            //catch (Exception ex)
165
            //{
166
            //    System.Console.Error.WriteLine($"Error processing file: {ex.Message}");
167
            //    return null;
168
            //}
169
        }
4✔
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