Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Factory balance #454

Draft
wants to merge 4 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Vic3ToHoI4lib.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@
<ClInclude Include="src\mappers\culture\culture_graphics_mapper.h" />
<ClInclude Include="src\mappers\culture\culture_graphics_mapper_importer.h" />
<ClInclude Include="src\mappers\culture\culture_graphics_mapping.h" />
<ClInclude Include="src\mappers\industry\industry_mapper.h" />
<ClInclude Include="src\mappers\ideology\ideology_mapper.h" />
<ClInclude Include="src\mappers\ideology\ideology_mapper_importer.h" />
<ClInclude Include="src\mappers\infrastructure\infrastructure_mapper.h" />
Expand Down Expand Up @@ -186,6 +187,7 @@
<ClCompile Include="src\mappers\country\country_mapper_creator.cpp" />
<ClCompile Include="src\mappers\culture\culture_graphics_mapper.cpp" />
<ClCompile Include="src\mappers\culture\culture_graphics_mapper_importer.cpp" />
<ClCompile Include="src\mappers\industry\industry_mapper.cpp" />
<ClCompile Include="src\mappers\ideology\ideology_mapper.cpp" />
<ClCompile Include="src\mappers\ideology\ideology_mapper_importer.cpp" />
<ClCompile Include="src\mappers\infrastructure\infrastructure_mapper.cpp" />
Expand Down
9 changes: 9 additions & 0 deletions Vic3ToHoI4lib.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,9 @@
<Filter Include="src\out_hoi4\national_focus">
<UniqueIdentifier>{6a73785e-ecc8-45e2-b5b4-a89ffff0628c}</UniqueIdentifier>
</Filter>
<Filter Include="src\mappers\industry">
<UniqueIdentifier>{d5fd8e32-66d1-4432-9d35-e933e67b6029}</UniqueIdentifier>
</Filter>
</ItemGroup>
<ItemGroup>
<ClInclude Include="src\vic3_to_hoi4_converter.h">
Expand Down Expand Up @@ -591,6 +594,9 @@
<ClInclude Include="src\mappers\infrastructure\infrastructure_mapper.h">
<Filter>src\mappers\infrastructure</Filter>
</ClInclude>
<ClInclude Include="src\mappers\industry\industry_mapper.h">
<Filter>src\mappers\industry</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="src\vic3_to_hoi4_converter.cpp">
Expand Down Expand Up @@ -902,6 +908,9 @@
<ClCompile Include="src\out_hoi4\national_focus\out_focus_tree.cpp">
<Filter>src\out_hoi4\national_focus</Filter>
</ClCompile>
<ClCompile Include="src\mappers\industry\industry_mapper.cpp">
<Filter>src\mappers\industry</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<Library Include="external\rakaly\rakaly.dll.lib">
Expand Down
2 changes: 1 addition & 1 deletion external/fmt
Submodule fmt updated 84 files
+8 −0 .github/dependabot.yml
+6 −0 .github/issue_template.md
+3 −2 .github/pull_request_template.md
+30 −0 .github/workflows/cifuzz.yml
+12 −1 .github/workflows/doc.yml
+42 −10 .github/workflows/linux.yml
+20 −2 .github/workflows/macos.yml
+65 −0 .github/workflows/scorecard.yml
+61 −21 .github/workflows/windows.yml
+100 −48 CMakeLists.txt
+1,146 −2 ChangeLog.rst
+1 −1 LICENSE.rst
+55 −38 README.rst
+11 −2 doc/CMakeLists.txt
+265 −158 doc/api.rst
+9 −6 doc/build.py
+1 −1 doc/index.rst
+138 −15 doc/syntax.rst
+1 −1 include/fmt/args.h
+469 −351 include/fmt/chrono.h
+85 −89 include/fmt/color.h
+50 −121 include/fmt/compile.h
+944 −1,242 include/fmt/core.h
+156 −1,213 include/fmt/format-inl.h
+2,064 −848 include/fmt/format.h
+0 −2 include/fmt/locale.h
+58 −88 include/fmt/os.h
+120 −54 include/fmt/ostream.h
+202 −192 include/fmt/printf.h
+326 −173 include/fmt/ranges.h
+452 −0 include/fmt/std.h
+86 −64 include/fmt/xchar.h
+40 −29 src/fmt.cc
+15 −96 src/format.cc
+101 −71 src/os.cc
+3 −3 support/Vagrantfile
+0 −43 support/appveyor-build.py
+0 −31 support/appveyor.yml
+0 −1 support/bazel/.bazelrc
+1 −1 support/bazel/.bazelversion
+1 −2 support/bazel/BUILD.bazel
+5 −4 support/bazel/README.md
+1 −1 support/build.gradle
+0 −70 support/cmake/cxx14.cmake
+4 −1 support/cmake/fmt-config.cmake.in
+6 −0 support/manage.py
+7 −0 support/rst2md.py
+30 −14 test/CMakeLists.txt
+1 −1 test/add-subdirectory-test/CMakeLists.txt
+1 −1 test/args-test.cc
+394 −23 test/chrono-test.cc
+6 −0 test/color-test.cc
+42 −4 test/compile-error-test/CMakeLists.txt
+2 −1 test/compile-fp-test.cc
+32 −39 test/compile-test.cc
+135 −240 test/core-test.cc
+18 −0 test/detect-stdfs.cc
+2 −0 test/enforce-checks-test.cc
+1 −1 test/find-package-test/CMakeLists.txt
+257 −151 test/format-impl-test.cc
+448 −385 test/format-test.cc
+1 −1 test/fuzzing/CMakeLists.txt
+2 −2 test/fuzzing/one-arg.cc
+2 −2 test/fuzzing/two-args.cc
+3 −1 test/gtest-extra-test.cc
+1 −6 test/gtest-extra.h
+1 −7 test/gtest/CMakeLists.txt
+2 −2 test/gtest/gmock-gtest-all.cc
+2 −2 test/mock-allocator.h
+36 −95 test/module-test.cc
+24 −69 test/os-test.cc
+50 −57 test/ostream-test.cc
+3 −9 test/posix-mock-test.cc
+0 −2 test/posix-mock.h
+14 −37 test/printf-test.cc
+195 −34 test/ranges-test.cc
+1 −1 test/scan-test.cc
+17 −14 test/scan.h
+1 −1 test/static-export-test/CMakeLists.txt
+246 −0 test/std-test.cc
+2 −3 test/test-main.cc
+4 −4 test/unicode-test.cc
+2 −6 test/util.h
+167 −93 test/xchar-test.cc
36 changes: 15 additions & 21 deletions src/hoi4_world/states/hoi4_states_converter.cpp
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
#include "src/hoi4_world/states/hoi4_states_converter.h"

#include <src/hoi4_world/world/hoi4_world.h>

#include <algorithm>
#include <cstdint>
#include <numeric>
Expand All @@ -10,8 +12,9 @@

#include "external/commonItems/Log.h"
#include "external/fmt/include/fmt/format.h"
#include "src/mappers/industry/industry_mapper.h"
#include "src/maps/map_data.h"

#include "src/out_hoi4/world/out_world.h"


namespace
Expand Down Expand Up @@ -739,16 +742,13 @@ void LogIndustryStats(const std::vector<hoi4::State>& hoi4_states,
}
}

Log(LogLevel::Info) << fmt::format("\t\tTotal factories: {} (vanilla hoi4 had {})",
out::OutputStats("Total factories",
civilian_factories + military_factories + dockyards,
default_civilian_factories + default_military_factories + default_dockyards);
Log(LogLevel::Info) << fmt::format("\t\t\tCivilian factories: {} (vanilla hoi4 had {})",
civilian_factories,
default_civilian_factories);
Log(LogLevel::Info) << fmt::format("\t\t\tMilitary factories: {} (vanilla hoi4 had {})",
military_factories,
default_military_factories);
Log(LogLevel::Info) << fmt::format("\t\t\tDockyards: {} (vanilla hoi4 had {})", dockyards, default_dockyards);
out::OutputStats("Civilian factories", civilian_factories, default_civilian_factories);
out::OutputStats("Military factories", military_factories, default_military_factories);
out::OutputStats("Dockyards", dockyards, default_dockyards);

for (const auto& [factories, num_states]: state_factory_numbers)
{
Log(LogLevel::Info) << fmt::format("\t\t\t{} states had {} factories", num_states, factories);
Expand Down Expand Up @@ -790,19 +790,14 @@ void LogManpowerStats(const std::vector<hoi4::State>& hoi4_states,
return total + state.second.GetManpower();
});

Log(LogLevel::Info) << fmt::format("\t\tManpower conversion: total={}, target={}, match={}%",
manpower,
default_manpower,
static_cast<double>(manpower) / static_cast<double>(default_manpower) * 100.0F);
out::OutputStats("Manpower", manpower, default_manpower);
}

void LogInfrastructure(mappers::InfrastructureMapper infrastructure_mapper)
{
Log(LogLevel::Info) << fmt::format("Infrastructure conversion: total={}, target={}, match={}%",
out::OutputStats("Infrastructure",
infrastructure_mapper.GetConvertedInfrastructure(),
infrastructure_mapper.GetTargetInfrastructure(),
static_cast<float>(infrastructure_mapper.GetConvertedInfrastructure()) /
static_cast<float>(infrastructure_mapper.GetTargetInfrastructure()) * 100.0F);
infrastructure_mapper.GetTargetInfrastructure());
Log(LogLevel::Info) << fmt::format("\tfudge factor is {}", infrastructure_mapper.GetFudgeFactor());
}

Expand Down Expand Up @@ -833,7 +828,7 @@ hoi4::States CreateStates(const vic3::World& source_world,
MapVic3ProvincesToStateNames(source_world.GetStateRegions());
std::map<std::string, std::string> hoi4_state_names_to_vic3_state_names;
mappers::InfrastructureMapper infrastructure_mapper(source_world.GetStates());

mappers::IndustryMapper industry_mapper(source_world);
for (const auto& vic3_state_id: vic3_state_ids_by_vic3_industry)
{
const auto& hoi4_provinces = vic3_state_id_to_hoi4_provinces.at(vic3_state_id);
Expand Down Expand Up @@ -876,10 +871,9 @@ hoi4::States CreateStates(const vic3::World& source_world,
return total + static_cast<int>(province_set.size());
});
int total_non_wasteland_provinces = static_cast<int>(hoi4_provinces.size()) - total_wasteland_provinces;

const int64_t total_manpower = vic3_state_itr->second.GetPopulation();
const float total_factories =
static_cast<float>(source_world.GetBuildings().GetTotalGoodSalesValueInState(vic3_state_id)) / 175'000.0F;
const float total_factories = industry_mapper.Map(source_world, vic3_state_id);
// static_cast<float>(source_world.GetBuildings().GetTotalGoodSalesValueInState(vic3_state_id)) / 175'000.0F;
for (const auto& province_set: final_connected_province_sets)
{
RecordStateNamesMapping(province_set,
Expand Down
1 change: 1 addition & 0 deletions src/hoi4_world/world/hoi4_world.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include <string>

#include "external/commonItems/Localization/LocalizationDatabase.h"
#include "external/fmt/include/fmt/format.h"
#include "src/hoi4_world/characters/hoi4_character.h"
#include "src/hoi4_world/countries/hoi4_country.h"
#include "src/hoi4_world/localizations/localizations.h"
Expand Down
121 changes: 121 additions & 0 deletions src/mappers/industry/industry_mapper.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
#include <numeric>
#include "industry_mapper.h"

namespace mappers
{

IndustryMapper::IndustryMapper(const vic3::World& source_world)
{
// TODO: make a config value
target_global_factories_ = 1226.0F;
factory_lower_balancing_limit_ = 100.0F;

// there's probably a faster way to do this

for (const auto& state : source_world.GetStates())
{
if(state.second.GetOwnerNumber().has_value())
{
int owner = state.second.GetOwnerNumber().value();
auto countryInfo =
std::find_if(this->countryBalances.begin(), this->countryBalances.end(), [owner](const CountryBalanceInformation& balanceInfo) {
return balanceInfo.country_id == owner;
});
if (countryInfo == this->countryBalances.end())
{
countryBalances.emplace_back(CountryBalanceInformation{owner,
source_world.GetBuildings().GetTotalGoodSalesValueInState(state.first)});
}
else
{
countryInfo->raw_vic3_factories += source_world.GetBuildings().GetTotalGoodSalesValueInState(state.first);
}
}
}

std::sort(this->countryBalances.begin(), this->countryBalances.end(), [](const auto& a, const auto& b) {
return a.raw_vic3_factories > b.raw_vic3_factories;
});
BalanceFactories();



float base_hoi4_factories = std::accumulate(this->countryBalances.begin(),
this->countryBalances.end(),
0.0F,
[](float sum, CountryBalanceInformation country) {
return sum + country.converted_vic3_factories;
});

target_global_factory_ratio_ = target_global_factories_ / base_hoi4_factories;
}

float IndustryMapper::Map(const vic3::World& source_world, int state_number)
{
const int owner = source_world.GetStates().at(state_number).GetOwnerNumber().value();
auto countryInfo = std::find_if(this->countryBalances.begin(),
this->countryBalances.end(),
[owner](const CountryBalanceInformation& balanceInfo) {
return balanceInfo.country_id == owner;
});
return source_world.GetBuildings().GetTotalGoodSalesValueInState(state_number) * target_global_factory_ratio_ *
countryInfo->converted_factory_ratio;
}


float max_power_ratio_by_overkill(float country_power, float prev_country_power)
{
float raw_power_ratio = country_power / prev_country_power;
if (raw_power_ratio <= 1.2)
{
return raw_power_ratio;
}
else
{
// played with in desmos, this power curve looks good
return 4 / 3 * log10(2*raw_power_ratio - 1) + 1;
}
}

void IndustryMapper::BalanceFactories()
{
{
auto iter = this->countryBalances.rbegin();
while (iter->raw_vic3_factories == 0)
{
++iter;
}
float prev_raw_vic3_factories = iter->raw_vic3_factories;
for (; iter != this->countryBalances.rend(); ++iter)
{
iter->max_ratio_by_competition = iter->raw_vic3_factories / prev_raw_vic3_factories;
iter->max_ratio_by_overkill = max_power_ratio_by_overkill(iter->raw_vic3_factories, prev_raw_vic3_factories);
prev_raw_vic3_factories = iter->raw_vic3_factories;
}
}

//and now, we adjust factory count
{
auto iter = this->countryBalances.rbegin();
while (iter->raw_vic3_factories == 0)
{
++iter;
}
float prev_converted_vic3_factories = iter->raw_vic3_factories;
for (; iter != this->countryBalances.rend(); ++iter)
{
if (iter->raw_vic3_factories < factory_lower_balancing_limit_)
{
iter->converted_vic3_factories = iter->raw_vic3_factories;
}
else
{
iter->converted_vic3_factories =
std::min(iter->max_ratio_by_competition, iter->max_ratio_by_overkill) * prev_converted_vic3_factories;
}
prev_converted_vic3_factories = iter->converted_vic3_factories;
iter->converted_factory_ratio = iter->converted_vic3_factories / iter->raw_vic3_factories;
}
}
}
}
40 changes: 40 additions & 0 deletions src/mappers/industry/industry_mapper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#pragma once
#include "src/vic3_world/world/vic3_world.h"

namespace mappers
{
struct CountryBalanceInformation
{
int country_id;
float raw_vic3_factories;
// factories(n)/factories(n-1): can't gain an advantage over the next strongest player via conversion
float max_ratio_by_competition;
// log2 formula: above 120% of next strongest player, adjust max power down to give a more balanced game
float max_ratio_by_overkill;

// output "balanced" factory count
float converted_vic3_factories;
// ratio of "balanced" factory count to initial count, so we can multiply by this for each state
float converted_factory_ratio;
auto operator<=>(const CountryBalanceInformation& other) const = default;
};

/// maps factories, and potentially balances.
class IndustryMapper
{
public:
IndustryMapper(const vic3::World& source_world);
float Map(const vic3::World& source_world, int state_number);

private:
std::vector<CountryBalanceInformation> countryBalances = {};
float target_global_factories_ = 0.0F;
float target_global_factory_ratio_ = 0.0F;
// below this limit, no balancing will take place.
// this allows small vic3 nations, which may have dramatic gdp differences, to retain
// that, while smoothing out the power of larger nations
float factory_lower_balancing_limit_ = 0.0F;

void BalanceFactories();
};
} // namespace mappers
1 change: 1 addition & 0 deletions src/maps/map_data_importer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ void maps::MapDataImporter::ImportProvinces(const commonItems::ModFilesystem& mo
}
}
}
Log(LogLevel::Progress) << 50 + (10 * y / height);
}
}

Expand Down
17 changes: 15 additions & 2 deletions src/out_hoi4/world/out_world.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,6 @@ void OutputBookmark(std::string_view output_name,

} // namespace



void out::OutputWorld(std::string_view output_name, const hoi4::World& world)
{
OutputCountries(output_name, world.GetCountries(), world.GetCharacters());
Expand All @@ -97,4 +95,19 @@ void out::OutputWorld(std::string_view output_name, const hoi4::World& world)
true,
world.GetGreatPowers(),
world.GetMajorPowers());
}

void out::OutputStats(const std::string& stat_name, double converted_value, double base_value)
{
double percent = static_cast<double>(converted_value - base_value) / static_cast<double>(base_value) * 100.0;
if (!std::isfinite(percent))
{
percent = 0.0;
}

Log(LogLevel::Info) << fmt::format("\t\t{} conversion: total={:.3f}, target={:.3f}, diff={:.3f}%",
stat_name,
converted_value,
base_value,
percent);
}
1 change: 1 addition & 0 deletions src/out_hoi4/world/out_world.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
namespace out
{

void OutputStats(const std::string& stat_name, double converted_value, double base_value);
void OutputWorld(std::string_view output_name, const hoi4::World& world);

} // namespace out
Expand Down
4 changes: 4 additions & 0 deletions src/vic3_world/states/vic3_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ namespace vic3

struct StateOptions
{
int id = 0;
std::optional<int> owner_number;
std::optional<std::string> owner_tag;
bool incorporated = false;
Expand All @@ -27,6 +28,7 @@ class State
public:
State() = default;
explicit State(StateOptions state_options):
id_(state_options.id),
owner_number_(state_options.owner_number),
owner_tag_(std::move(state_options.owner_tag)),
incorporated_(state_options.incorporated),
Expand All @@ -37,6 +39,7 @@ class State
{
}

[[nodiscard]] const int GetId() const { return id_; }
[[nodiscard]] const std::optional<int>& GetOwnerNumber() const { return owner_number_; }
[[nodiscard]] const std::optional<std::string>& GetOwnerTag() const { return owner_tag_; }
[[nodiscard]] bool IsIncorporated() const { return incorporated_; }
Expand All @@ -50,6 +53,7 @@ class State
bool operator==(const State&) const = default;

private:
int id_;
std::optional<int> owner_number_;
std::optional<std::string> owner_tag_;
bool incorporated_ = false;
Expand Down
Loading