Skip to content

Commit

Permalink
Fix hidden recipe in case of duplicate names
Browse files Browse the repository at this point in the history
  • Loading branch information
adepierre committed Oct 1, 2024
1 parent 7e562f8 commit 182e6a7
Show file tree
Hide file tree
Showing 5 changed files with 47 additions and 35 deletions.
2 changes: 1 addition & 1 deletion assets/satisfactory.json
Original file line number Diff line number Diff line change
Expand Up @@ -6676,7 +6676,7 @@
]
},
{
"name": "Turbo Rifle Ammo",
"name": "Turbo Rifle Ammo (1)",
"alternate": false,
"time": 12.0,
"building": "Blender",
Expand Down
7 changes: 4 additions & 3 deletions ficsit-companion/include/game_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
#include <unordered_map>
#include <vector>

#include "building.hpp"
#include "recipe.hpp"
struct Building;
struct Item;
struct Recipe;

namespace Data
{
Expand All @@ -24,5 +25,5 @@ namespace Data
const std::unordered_map<std::string, std::unique_ptr<Building>>& Buildings();

/// @brief Get all known recipes
const std::vector<Recipe>& Recipes();
const std::vector<std::unique_ptr<Recipe>>& Recipes();
}
41 changes: 21 additions & 20 deletions ficsit-companion/src/app.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "link.hpp"
#include "node.hpp"
#include "pin.hpp"
#include "recipe.hpp"
#include "utils.hpp"

// For InputText with std::string
Expand Down Expand Up @@ -146,9 +147,9 @@ void App::LoadSettings()

for (const auto& r : Data::Recipes())
{
if (r.alternate)
if (r->alternate)
{
settings.unlocked_alts[&r] = json.contains("unlocked_alts") && json["unlocked_alts"].contains(r.name.substr(1)) && json["unlocked_alts"][r.name.substr(1)].get<bool>();
settings.unlocked_alts[r.get()] = json.contains("unlocked_alts") && json["unlocked_alts"].contains(r->name.substr(1)) && json["unlocked_alts"][r->name.substr(1)].get<bool>();
}
}

Expand Down Expand Up @@ -266,9 +267,9 @@ void App::Deserialize(const std::string& s)
auto get_recipe = [&](const std::string& name) -> const Recipe* {
for (const auto& r : Data::Recipes())
{
if (r.name == name)
if (r->name == name)
{
return &r;
return r.get();
}
}
return nullptr;
Expand Down Expand Up @@ -1091,9 +1092,9 @@ void App::RenderLeftPanel()
settings.unlocked_alts = {};
for (const auto& r : Data::Recipes())
{
if (r.alternate)
if (r->alternate)
{
settings.unlocked_alts[&r] = true;
settings.unlocked_alts[r.get()] = true;
}
}
SaveSettings();
Expand All @@ -1107,9 +1108,9 @@ void App::RenderLeftPanel()
settings.unlocked_alts = {};
for (const auto& r : Data::Recipes())
{
if (r.alternate)
if (r->alternate)
{
settings.unlocked_alts[&r] = false;
settings.unlocked_alts[r.get()] = false;
}
}
SaveSettings();
Expand Down Expand Up @@ -1819,7 +1820,7 @@ void App::AddNewNode()
ImGui::Separator();
// Stores the recipe index and a "match score" to sort them in the display
std::vector<std::pair<int, size_t>> recipe_indices;
const std::vector<Recipe>& recipes = Data::Recipes();
const std::vector<std::unique_ptr<Recipe>>& recipes = Data::Recipes();
recipe_indices.reserve(recipes.size());
// If this is already linked to another node
// only display matching recipes
Expand All @@ -1832,7 +1833,7 @@ void App::AddNewNode()
{
break;
}
const std::vector<CountedItem>& matching_pins = new_node_pin->direction == ax::NodeEditor::PinKind::Input ? recipes[i].outs : recipes[i].ins;
const std::vector<CountedItem>& matching_pins = new_node_pin->direction == ax::NodeEditor::PinKind::Input ? recipes[i]->outs : recipes[i]->ins;
for (int j = 0; j < matching_pins.size(); ++j)
{
if (matching_pins[j].item->new_line_name == item_name)
Expand Down Expand Up @@ -1872,11 +1873,11 @@ void App::AddNewNode()
// A recipe goes on top if it matched the search string "before" another
// If they both matched at the same place, the alternate goes after
auto scored_recipe_sorting = [&](const std::pair<int, size_t>& a, const std::pair<int, size_t>& b) {
return a.second < b.second || (a.second == b.second && !recipes[a.first].alternate && recipes[b.first].alternate);
return a.second < b.second || (a.second == b.second && !recipes[a.first]->alternate && recipes[b.first]->alternate);
};
for (int i = 0; i < recipes.size(); ++i)
{
if (const size_t pos = recipes[i].FindInName(recipe_filter); pos != std::string::npos)
if (const size_t pos = recipes[i]->FindInName(recipe_filter); pos != std::string::npos)
{
recipe_indices.push_back({ i, pos });
}
Expand All @@ -1886,9 +1887,9 @@ void App::AddNewNode()

for (int i = 0; i < recipes.size(); ++i)
{
if (recipes[i].FindInName(recipe_filter) == std::string::npos)
if (recipes[i]->FindInName(recipe_filter) == std::string::npos)
{
if (const size_t pos = recipes[i].FindInIngredients(recipe_filter); pos != std::string::npos)
if (const size_t pos = recipes[i]->FindInIngredients(recipe_filter); pos != std::string::npos)
{
recipe_indices.push_back({ i, pos });
}
Expand Down Expand Up @@ -1916,21 +1917,21 @@ void App::AddNewNode()

for (const auto [i, score_ignored] : recipe_indices)
{
if (settings.hide_spoilers && recipes[i].is_spoiler)
if (settings.hide_spoilers && recipes[i]->is_spoiler)
{
continue;
}
ImGui::TableNextRow();
ImGui::TableSetColumnIndex(0);
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
if (recipes[i].alternate && ImGui::Checkbox(("##checkbox" + recipes[i].name).c_str(), &settings.unlocked_alts.at(&recipes[i])))
if (recipes[i]->alternate && ImGui::Checkbox(("##checkbox" + recipes[i]->name).c_str(), &settings.unlocked_alts.at(recipes[i].get())))
{
SaveSettings();
}
ImGui::PopStyleVar();
ImGui::TableSetColumnIndex(1);
ImGui::BeginDisabled(recipes[i].alternate && !settings.unlocked_alts.at(&recipes[i]));
if (ImGui::MenuItem(recipes[i].display_name.c_str()))
ImGui::BeginDisabled(recipes[i]->alternate && !settings.unlocked_alts.at(recipes[i].get()));
if (ImGui::MenuItem(recipes[i]->display_name.c_str()))
{
recipe_index = i + 2;
// Need to duplicate the EndDisabled because of the break
Expand All @@ -1940,7 +1941,7 @@ void App::AddNewNode()
ImGui::EndDisabled();
ImGui::TableSetColumnIndex(2);

recipes[i].Render(false);
recipes[i]->Render(false);
}
ImGui::EndTable();

Expand All @@ -1956,7 +1957,7 @@ void App::AddNewNode()
}
else
{
nodes.emplace_back(std::make_unique<CraftNode>(GetNextId(), &recipes[recipe_index - 2], std::bind(&App::GetNextId, this)));
nodes.emplace_back(std::make_unique<CraftNode>(GetNextId(), recipes[recipe_index - 2].get(), std::bind(&App::GetNextId, this)));
}
ax::NodeEditor::SetNodePosition(nodes.back()->id, new_node_position);
if (new_node_pin != nullptr)
Expand Down
23 changes: 12 additions & 11 deletions ficsit-companion/src/game_data.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
#include <fstream>
#include <stdexcept>

#include "building.hpp"
#include "game_data.hpp"
#include "json.hpp"
#include "recipe.hpp"

namespace Data
{
Expand All @@ -12,7 +14,7 @@ namespace Data
std::string version;
std::unordered_map<std::string, std::unique_ptr<Item>> items;
std::unordered_map<std::string, std::unique_ptr<Building>> buildings;
std::vector<Recipe> recipes;
std::vector<std::unique_ptr<Recipe>> recipes;
}

void LoadData(const std::string& game)
Expand Down Expand Up @@ -45,14 +47,9 @@ namespace Data
items[name] = std::make_unique<Item>(name, i["icon"].get_string());
}

// Trick to sort the recipes alphabetically using std::map default sorting
Json::Value ordered_recipes;
for (const auto& r : data["recipes"].get_array())
{
ordered_recipes[r["name"].get_string()] = r;
}
const Json::Array& json_recipes = data["recipes"].get_array();

for (const auto& [name, r] : ordered_recipes.get_object())
for (const auto& r : json_recipes)
{
const int time = static_cast<int>(r["time"].get<double>());
std::vector<CountedItem> inputs;
Expand All @@ -65,15 +62,19 @@ namespace Data
{
outputs.emplace_back(CountedItem(items.at(o["name"].get_string()).get(), FractionalNumber(std::to_string(o["amount"].get<double>() * 60.0) + "/" + std::to_string(time))));
}
recipes.emplace_back(Recipe(
recipes.emplace_back(std::make_unique<Recipe>(
inputs,
outputs,
buildings.at(r["building"].get_string()).get(),
r["alternate"].get<bool>(),
name,
r["name"].get_string(),
r.contains("spoiler") && r["spoiler"].get<bool>()
));
}

std::stable_sort(recipes.begin(), recipes.end(), [](const std::unique_ptr<Recipe>& a, const std::unique_ptr<Recipe>& b) {
return a->name < b->name;
});
}

const std::string& Version()
Expand All @@ -91,7 +92,7 @@ namespace Data
return buildings;
}

const std::vector<Recipe>& Recipes()
const std::vector<std::unique_ptr<Recipe>>& Recipes()
{
return recipes;
}
Expand Down
9 changes: 9 additions & 0 deletions scripts/data_extractor.py
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,15 @@ def parse_counted_item_list(s: str, items: Dict):
"outputs": parse_counted_item_list(recipe["mProduct"], items)
}

# Make sure all recipe names are unique
recipes_names_counter = {}
for r in recipes.values():
if r["name"] in recipes_names_counter:
recipes_names_counter[r["name"]] += 1
r["name"] = f"{r['name']} ({recipes_names_counter[r['name']] - 1})"
else:
recipes_names_counter[r["name"]] = 1

# Copy icons for each used item
if os.path.exists("icons"):
shutil.rmtree("icons")
Expand Down

0 comments on commit 182e6a7

Please sign in to comment.