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

Econ 2.0 Buildings #572

Open
wants to merge 64 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
64 commits
Select commit Hold shift + click to select a range
397bbf9
Estimate PM prevalences
gawquon Aug 17, 2024
e48d932
Estimate Building inputs/outputs/jobs
gawquon Aug 18, 2024
5a00583
get culture breakdown
gawquon Aug 18, 2024
71e6385
job tracking object
gawquon Aug 19, 2024
17cc63d
load state's subsistence building
gawquon Aug 19, 2024
c4e9889
Initialization lists MarketJobs
gawquon Aug 19, 2024
3707684
woops WIP Market debug + actual init list
gawquon Aug 19, 2024
d17de6f
fix bad commit
gawquon Aug 20, 2024
de5f542
debugging table fxns
gawquon Aug 20, 2024
5bed713
algerbra ftw
gawquon Aug 20, 2024
6709d5d
get state modifier effects by building
gawquon Aug 20, 2024
5bdc8a7
algebra go brr
gawquon Aug 20, 2024
6fc79ca
outline stiching together all predicitve/tracking of the market
gawquon Aug 21, 2024
e1a870b
Objectify Oacket for unit tests
gawquon Aug 23, 2024
a28c3cc
Packet unit tests
gawquon Aug 25, 2024
5696ec5
setup MarketTracker
gawquon Aug 28, 2024
4a6f032
progess marketTracker
gawquon Aug 29, 2024
51fdd02
start createPeasants
gawquon Aug 30, 2024
71805ab
Create peasants job part
gawquon Aug 30, 2024
77536fd
marketJobs 3.0
gawquon Aug 31, 2024
39e5a50
begin the stitch
gawquon Aug 31, 2024
ab3ad98
Load unemployed as a popType
gawquon Aug 31, 2024
162ae4d
debugging
gawquon Aug 31, 2024
bbdf8ad
string bodge
gawquon Sep 1, 2024
6093d6a
continue the stitch
gawquon Sep 1, 2024
299db94
The subsistence shuffle
gawquon Sep 4, 2024
a9a066a
prep hard-coded building types for market entry
gawquon Sep 4, 2024
fd6425f
inverted boolean bugfix
gawquon Sep 6, 2024
322bd38
minor debugs
gawquon Sep 6, 2024
5080a53
add unit test for law-based PMs
gawquon Oct 5, 2024
9a495cf
Load in Urbanization into Building Groups
gawquon Oct 12, 2024
559913e
Track jobs from Urban Centers
gawquon Oct 12, 2024
6260693
Lawbound PMs
gawquon Oct 14, 2024
818e18a
urban center PM config
gawquon Oct 15, 2024
5fb0369
prep hardcoded market injection
gawquon Oct 19, 2024
363c26e
hardcoded building integration
gawquon Oct 19, 2024
fb5710b
Fix tripling output goods
gawquon Oct 21, 2024
f83ab0d
remove debugs
gawquon Oct 21, 2024
482f8a7
merge main
gawquon Oct 21, 2024
c37d738
clang
gawquon Oct 21, 2024
2781c90
comments & cleanup
gawquon Oct 21, 2024
0fc4b0e
Make gcc happy
gawquon Oct 21, 2024
d9a5b0a
mute unhandled warnings, for now
gawquon Oct 21, 2024
4bf58ae
Disable premature test
gawquon Oct 21, 2024
7574566
less hardcoding
gawquon Oct 22, 2024
56e4b77
replace iterate with index
gawquon Oct 24, 2024
351835e
semantics
gawquon Oct 24, 2024
3dcb9c5
typedefs
gawquon Oct 24, 2024
aaa791a
setStrata
gawquon Oct 24, 2024
784b68e
investor weights -> fractions
gawquon Oct 24, 2024
4b913ca
more percents -> fraction
gawquon Oct 24, 2024
c19ec80
remove optional
gawquon Nov 1, 2024
4d9cebb
document ProductionMethod::getType
gawquon Nov 12, 2024
e0f03ed
Document Packet.h
gawquon Nov 12, 2024
a08d611
document PM walking expectations
gawquon Nov 12, 2024
fce67d4
add country tests
gawquon Nov 12, 2024
56079a3
clang
gawquon Nov 12, 2024
f6c0b1c
use Idhrendur's simplification from review
gawquon Nov 12, 2024
ac96954
rename tests
gawquon Nov 12, 2024
845a572
Merge branch 'econ-2.0' of https://github.com/gawquon/EU4toVic3 into …
gawquon Nov 12, 2024
00fae37
clang
gawquon Nov 13, 2024
34ca0f4
added guardrails to PM resource usage/output calculations
gawquon Nov 13, 2024
2efdda0
functionalize workers + dependants calculations
gawquon Nov 13, 2024
f89677c
validate presence of ownership buildings in ownership employment data.
gawquon Nov 13, 2024
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
4 changes: 2 additions & 2 deletions EU4ToVic3/Data_Files/configurables/economy/ownership.txt
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
# Decide how ownership will be split among Vic 3 buildings.
# Keywords are 'local', 'national', 'national_service', 'building_manor_house', 'building_financial_district'
# colonial = 0.2 ### This shifts 20% of the aristocracy too be owned by an overlord if applicable; default is 0%
# colonial = 0.2 ### This shifts 20% of the aristocracy to be owned by an overlord if applicable; default is 0%
# financial = 0.1 ### This shifts 10% of the capital to the nation's capital; default is 0%
# recognized = yes ### This prevents capitalists from owning these buildings if a nation is unrecognized
# recognized = yes ### This prevents an ownership building type from owning these buildings if a nation is unrecognized

agriculture = {
ownership = {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,83 +1,90 @@
# Linked buildings will walk towards the PMs specified until the PM is reached. or the next step is invalid due to tech.
# The percent is the percent of building levels that will try to move off of default to adopt the defined PM. It is assumed to be 1(100%) unless specified.
# Ownership PMs should be marked with law_bound = yes

# building_government_administration # SPECIAL CASE government administration links will be ignored even if defined.

##### Development
building_port = {
pm = { name = pm_basic_port }
pm = { name = pm_basic_port }
}
building_barracks = {
pm = { name = pm_general_training }
pm = { name = pm_general_training }
}
building_naval_base = {
pm = { name = pm_power_of_the_purse }
pm = { name = pm_power_of_the_purse }
}

##### Urban
building_urban_center = {
pm = { name = pm_market_squares }
pm = { name = pm_gas_streetlights }
pm = { name = pm_free_urban_clergy law_bound = yes }
}
building_tooling_workshops = {
pm = { name = pm_pig_iron }
pm = { name = pm_pig_iron }
}
building_glassworks = {
pm = { name = pm_leaded_glass }
pm = { name = pm_leaded_glass }
}
building_paper_mills = {
pm = { name = pm_sulfite_pulping percent = 0.4 }
pm = { name = pm_sulfite_pulping percent = 0.4 }
}
building_furniture_manufacturies = {
pm = { name = pm_lathe }
pm = { name = pm_luxury_furniture percent = 0.5 }
pm = { name = pm_lathe }
pm = { name = pm_luxury_furniture percent = 0.5 }
}
building_textile_mills = {
pm = { name = pm_dye_workshops percent = 0.05 }
pm = { name = pm_craftsman_sewing percent = 0.1 }
pm = { name = pm_dye_workshops percent = 0.05 }
pm = { name = pm_craftsman_sewing percent = 0.1 }
}
building_shipyards = {
pm = { name = pm_complex_shipbuilding }
pm = { name = pm_complex_shipbuilding }
}
building_military_shipyards = {
pm = { name = pm_military_shipbuilding_wooden }
pm = { name = pm_military_shipbuilding_wooden }
}
building_arms_industry = {
pm = { name = pm_rifles }
pm = { name = pm_rifles }
}
building_artillery_foundries = {
pm = { name = pm_cannons }
pm = { name = pm_cannons }
}
building_food_industry = {
pm = { name = pm_pot_stills }
pm = { name = pm_pot_stills }
}
building_chemical_plants = {
pm = { name = pm_nitrogen_fixation }
pm = { name = pm_nitrogen_fixation }
}

##### Rural
building_logging_camp = {
pm = { name = pm_saw_mills }
pm = { name = pm_hardwood percent = 0.4 }
pm = { name = pm_saw_mills }
pm = { name = pm_hardwood percent = 0.4 }
}
### Farms
building_rye_farm = {
pm = { name = pm_potatoes percent = 0.15 }
pm = { name = pm_potatoes percent = 0.15 }
}
building_wheat_farm = {
pm = { name = pm_citrus_orchards percent = 0.2 }
pm = { name = pm_citrus_orchards percent = 0.2 }
}
building_millet_farm = {
pm = { name = pm_soil_enriching_farming percent = 0.2 }
pm = { name = pm_soil_enriching_farming percent = 0.2 }
}
building_maize_farm = {
pm = { name = pm_citrus_orchards percent = 0.2 }
pm = { name = pm_citrus_orchards percent = 0.2 }
}
### Mines
building_coal_mine = {
pm = { name = pm_atmospheric_engine_pump_building_coal_mine }
pm = { name = pm_atmospheric_engine_pump_building_coal_mine }
}
building_iron_mine = {
pm = { name = pm_atmospheric_engine_pump_building_iron_mine }
pm = { name = pm_atmospheric_engine_pump_building_iron_mine }
}
building_gold_mine = {
pm = { name = pm_atmospheric_engine_pump_building_gold_mine }
pm = { name = pm_atmospheric_engine_pump_building_gold_mine }
}
building_sulfur_mine = {
pm = { name = pm_atmospheric_engine_pump_building_sulfur_mine }
pm = { name = pm_atmospheric_engine_pump_building_sulfur_mine }
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ struct PMRule
{
std::string pm;
double percent = 1.0;
bool lawBound = false;

bool operator==(const PMRule&) const = default;
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,5 +17,8 @@ void mappers::ProductionMethodEntry::registerKeys()
registerKeyword("percent", [this](std::istream& theStream) {
rule.percent = commonItems::getDouble(theStream);
});
registerKeyword("law_bound", [this](std::istream& theStream) {
rule.lawBound = commonItems::getString(theStream) == "yes";
});
registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
}
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,9 @@ std::pair<std::string, std::string> mappers::ProductionMethodMapper::pickPM(cons
const std::map<std::string, V3::ProductionMethodGroup>& PMGroups)
{
// NOTE(Gawquon): This works for most PMs, but is not guaranteed to work for ownership PMs.
// Added a workaround for ownership PMs in Econ 2.0, but a unifying theory of PMs would be nice.
// Workaround will break for ownership PMs which require tech, should be none at the start.

// This is just a basic version that will support every use-case we currently care about.
for (const auto& PMGroup: PMGroups | std::views::values)
{
Expand Down Expand Up @@ -191,6 +194,110 @@ std::pair<std::string, std::string> mappers::ProductionMethodMapper::pickPM(cons
return {"", ""};
}

int mappers::ProductionMethodMapper::walkPMsTechbound(const std::vector<std::string>& groupPMs,
const V3::Country& country,
const std::string& targetName,
const std::map<std::string, V3::ProductionMethod>& PMs)
{
// Validate every PM in group
for (const auto& PM: groupPMs)
{
if (!PMs.contains(PM))
{
Log(LogLevel::Error) << "Unknown PM: " << PM << ".";
return 0;
}
}

// Walk the group, we're looking for the most advanced PM allowed by tech, up to our target PM.
int pick = 0;
for (const auto& PM: groupPMs)
{
if (!country.hasAnyOfTech(PMs.at(PM).getUnlockingTechs()))
return std::max(pick - 1, 0);
if (PM == targetName)
return pick;
++pick;
}
return std::max(pick - 1, 0);
}

// No explicit target, finds the first PM allowed by law.
int mappers::ProductionMethodMapper::walkPMsLawbound(const std::vector<std::string>& groupPMs,
const V3::Country& country,
const std::map<std::string, V3::ProductionMethod>& PMs)
{
int pick = 0;

for (const auto& PM: groupPMs)
{
const auto& thePM = PMs.at(PM);
const bool hasUnlockingLaws = country.hasAnyOfLawUnlocking(thePM.getUnlockingLaws());
const bool hasBlockingLaws = country.hasAnyOfLawBlocking(thePM.getBlockingLaws());

if (hasUnlockingLaws && !hasBlockingLaws)
return std::max(pick, 0);
++pick;
}
return 0; // Nothing is legal, just go with default PM.
}

std::map<mappers::PmGroup, std::tuple<mappers::PmIndex, mappers::PmFraction>> mappers::ProductionMethodMapper::estimatePMs(const V3::Country& country,
const std::map<std::string, V3::ProductionMethod>& PMs,
const std::map<std::string, V3::ProductionMethodGroup>& PMGroups,
const std::map<std::string, V3::Building>& buildings) const
{
// PMs are not necessarily unique to a building, but PMGroups are.
// Additionally, no PM will appear twice in the same building.
std::map<std::string, std::tuple<int, double>> expectedPMs; // PMGroup -> (expected PM index, %)

// Configuration based PMs, checked against available tech.
for (const auto& [buildingName, building]: buildings)
{
if (const auto& rulesIter = buildingToRules.find(buildingName); rulesIter != buildingToRules.end())
{
const auto& rules = rulesIter->second;
for (const auto& PMGroup: building.getPMGroups())
{
bool flag = false;
for (int ruleIndex = 0; ruleIndex < rules.size() && !flag; ruleIndex++)
{
const auto& groupPMs = PMGroups.at(PMGroup).getPMs();
for (const auto& PM: groupPMs)
{
if (const auto& rule = rules[ruleIndex]; rule.pm == PM)
{
if (rule.lawBound)
expectedPMs.emplace(PMGroup, std::make_tuple(walkPMsLawbound(groupPMs, country, PMs), rule.percent));
else
expectedPMs.emplace(PMGroup, std::make_tuple(walkPMsTechbound(groupPMs, country, PM, PMs), rule.percent));

flag = true;
break;
}
}
}
if (!flag)
expectedPMs.emplace(PMGroup, std::tuple{0, 1.0});
}
}
}

// Law based PMs (Subsistence & Clergy)
for (const auto& [buildingName, building]: buildings)
{
if (buildingName.find("subsistence") == std::string::npos)
continue;

for (const auto& PMGroup: building.getPMGroups())
{
const auto& groupPMs = PMGroups.at(PMGroup).getPMs();
expectedPMs.emplace(PMGroup, std::make_tuple(walkPMsLawbound(groupPMs, country, PMs), 1));
}
}
return expectedPMs;
}

////////////////////////////////////////// Subset-sum fxns
std::vector<std::shared_ptr<V3::Building>> mappers::ProductionMethodMapper::subSetSum(const std::vector<std::shared_ptr<V3::Building>>& subSet, int targetVal)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ class Country;
} // namespace V3
namespace mappers
{
using PmIndex = int;
using PmFraction = double;
using PmGroup = std::string;
class ProductionMethodMapper: commonItems::parser
{
public:
Expand All @@ -23,6 +26,12 @@ class ProductionMethodMapper: commonItems::parser

[[nodiscard]] const auto& getRules() const { return buildingToRules; }

// demandEstimates helper
[[nodiscard]] std::map<PmGroup, std::tuple<PmIndex, PmFraction>> estimatePMs(const V3::Country& country,
const std::map<std::string, V3::ProductionMethod>& PMs,
const std::map<std::string, V3::ProductionMethodGroup>& PMGroups,
const std::map<std::string, V3::Building>& buildings) const;

private:
void registerKeys();

Expand All @@ -36,6 +45,13 @@ class ProductionMethodMapper: commonItems::parser
const std::set<std::string>& buildingPMGroups,
const std::map<std::string, V3::ProductionMethod>& PMs,
const std::map<std::string, V3::ProductionMethodGroup>& PMGroups);
[[nodiscard]] static int walkPMsTechbound(const std::vector<std::string>& groupPMs,
const V3::Country& country,
const std::string& targetName,
const std::map<std::string, V3::ProductionMethod>& PMs);
[[nodiscard]] static int walkPMsLawbound(const std::vector<std::string>& groupPMs,
const V3::Country& country,
const std::map<std::string, V3::ProductionMethod>& PMs);

// Subset-sum
static std::vector<std::shared_ptr<V3::Building>> subSetSum(const std::vector<std::shared_ptr<V3::Building>>& subSet, int targetVal);
Expand Down
3 changes: 3 additions & 0 deletions EU4ToVic3/Source/V3World/ClayManager/State/State.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,9 @@ void V3::State::loadState(std::istream& theStream)

void V3::State::registerKeys()
{
registerKeyword("subsistence_building", [this](std::istream& theStream) {
subsistenceBuilding = commonItems::getString(theStream);
});
registerKeyword("provinces", [this](std::istream& theStream) {
for (const auto& provinceName: commonItems::getStrings(theStream))
{
Expand Down
2 changes: 2 additions & 0 deletions EU4ToVic3/Source/V3World/ClayManager/State/State.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ class State: commonItems::parser
[[nodiscard]] const auto& getTraits() const { return traits; }
[[nodiscard]] const auto& getCappedResources() const { return cappedResources; }
[[nodiscard]] const auto& getArableResources() const { return arableResources; }
[[nodiscard]] const auto& getSubsistenceBuilding() const { return subsistenceBuilding; }

[[nodiscard]] ProvinceMap getUnassignedProvinces() const;
[[nodiscard]] bool hasUnassignedProvinces() const;
Expand All @@ -65,6 +66,7 @@ class State: commonItems::parser
std::vector<std::string> traits; // state_trait_natural_harbors
std::map<std::string, int> cappedResources; // RGO and arable land potential
std::vector<std::string> arableResources; // Which buildings can be built on arable land
std::string subsistenceBuilding; // building_subsistence_fishing_villages
std::set<std::string> homelands;
};
} // namespace V3
Expand Down
36 changes: 25 additions & 11 deletions EU4ToVic3/Source/V3World/ClayManager/State/StateModifier.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -73,19 +73,24 @@ double V3::StateModifier::getAllBonuses(const std::map<std::string, double>& mod
return std::accumulate(modifiers.begin(), modifiers.end(), 0.0);
}

std::optional<double> V3::StateModifier::getBuildingGroupModifier(const std::string& buildingGroup, const BuildingGroups& bgs) const
double V3::StateModifier::getBuildingGroupModifier(const std::string& buildingGroup, const BuildingGroups& bgs) const
{
std::optional currentGroup = buildingGroup;
do
double modifierTotal = 0;
for (const auto& [groupName, modifier]: buildingGroupModifiers)
{
if (const auto& mod = buildingGroupModifiers.find(currentGroup.value()); mod != buildingGroupModifiers.end())
{
return mod->second;
}
currentGroup = bgs.tryGetParentName(currentGroup);
} while (currentGroup);
std::optional currentGroup = buildingGroup;

return std::nullopt;
do
{
if (groupName == currentGroup.value())
{
modifierTotal += modifier;
break;
}
currentGroup = bgs.tryGetParentName(currentGroup);
} while (currentGroup);
}
return modifierTotal;
}

std::optional<double> V3::StateModifier::getBuildingModifier(const std::string& building) const
Expand All @@ -104,4 +109,13 @@ std::optional<double> V3::StateModifier::getGoodsModifier(const std::string& goo
return possibleModifier->second;
}
return std::nullopt;
}
}

double V3::StateModifier::calcBuildingModifiers(const Building& building, const BuildingGroups& buildingGroups) const
{
const auto& modifierIter = buildingModifiers.find(building.getName());
double modifierTotal = modifierIter == buildingModifiers.end() ? 0 : modifierIter->second;
modifierTotal += getBuildingGroupModifier(building.getBuildingGroup(), buildingGroups);

return modifierTotal;
}
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#ifndef STATE_MODIFIER_H
#define STATE_MODIFIER_H
#include "EconomyManager/Building/Building.h"
#include "EconomyManager/Building/BuildingGroups.h"
#include "Parser.h"

Expand All @@ -20,9 +21,10 @@ class StateModifier: commonItems::parser
[[nodiscard]] const auto& getBuildingModifiersMap() const { return buildingModifiers; }
[[nodiscard]] const auto& getGoodsModifiersMap() const { return goodsModifiers; }
[[nodiscard]] static double getAllBonuses(const std::map<std::string, double>& modifierMap); // Sum of all modifiers off a single type
[[nodiscard]] std::optional<double> getBuildingGroupModifier(const std::string& buildingGroup, const BuildingGroups& bgs) const;
[[nodiscard]] double getBuildingGroupModifier(const std::string& buildingGroup, const BuildingGroups& bgs) const;
[[nodiscard]] std::optional<double> getBuildingModifier(const std::string& building) const;
[[nodiscard]] std::optional<double> getGoodsModifier(const std::string& good) const;
[[nodiscard]] double calcBuildingModifiers(const Building& building, const BuildingGroups& buildingGroups) const;

private:
void registerKeys();
Expand Down
Loading