Skip to content

Commit

Permalink
Title history removal fix (#63)
Browse files Browse the repository at this point in the history
* Vanilla CK3 title history: store current title holder

* Update commonItems

* Remove invalid landless titles

* Fixed mod copying

* Update CK3World.cpp
  • Loading branch information
IhateTrains authored Oct 11, 2020
1 parent a130faa commit 8c78f8f
Show file tree
Hide file tree
Showing 7 changed files with 124 additions and 20 deletions.
1 change: 1 addition & 0 deletions ImperatorToCK3.sln.DotSettings
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<s:Boolean x:Key="/Default/UserDictionary/Words/=IMPERATOR/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Incontinentia/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Invicta/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=Jure/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=librakaly/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=paradoxian/@EntryIndexedValue">True</s:Boolean>
<s:Boolean x:Key="/Default/UserDictionary/Words/=passant/@EntryIndexedValue">True</s:Boolean>
Expand Down
2 changes: 1 addition & 1 deletion ImperatorToCK3/Data_Files/fronter-configuration.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ requiredFolder = {
searchPathID = 1158310
}
requiredFolder = {
name = CK3ModsDirectory
name = targetGameModPath
displayName = CK3MOD
tooltip = CK3MODTIP
mandatory = true
Expand Down
41 changes: 33 additions & 8 deletions ImperatorToCK3/Source/CK3/CK3World.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ CK3::World::World(const ImperatorWorld::World& impWorld, const Configuration& th
landedTitles.loadTitles(theConfiguration.getCK3Path() + "/game/common/landed_titles/00_landed_titles.txt");
// Load vanilla titles history
titlesHistory = TitlesHistory(theConfiguration);

importImperatorCountries(impWorld);

// Now we can deal with provinces since we know to whom to assign them. We first import vanilla province data.
Expand All @@ -43,7 +43,8 @@ CK3::World::World(const ImperatorWorld::World& impWorld, const Configuration& th


linkCountiesToTitleHolders(impWorld);
insertVanillaNonCountiesToTitles(impWorld);
importVanillaNonCountyNonBaronyTitles(impWorld);
removeInvalidLandlessTitles();
}

void CK3::World::importImperatorCharacters(const ImperatorWorld::World& impWorld, const bool ConvertBirthAndDeathDates = true, const date endDate = date(867,1,1))
Expand Down Expand Up @@ -263,6 +264,7 @@ void CK3::World::linkCountiesToTitleHolders(const ImperatorWorld::World& impWorl
else // county is probably outside of Imperator map
{
auto vanillaHistory = titlesHistory.popTitleHistory(name);
if (titlesHistory.currentHolderIdMap[name]) countyTitle->holder = *titlesHistory.currentHolderIdMap[name];
if (vanillaHistory) countyTitle->historyString = *vanillaHistory;
}
}
Expand All @@ -273,27 +275,34 @@ void CK3::World::linkCountiesToTitleHolders(const ImperatorWorld::World& impWorl
}


void CK3::World::insertVanillaNonCountiesToTitles(const ImperatorWorld::World& impWorld)
{
void CK3::World::importVanillaNonCountyNonBaronyTitles(const ImperatorWorld::World& impWorld)
{
for (const auto& [name, landedTitle] : landedTitles.getFoundTitles())
{
if (name.find("c_") != 0 && name.find("b_") != 0 ) // title is a duchy or higher
{
auto toInsert = true;
// important check: if any of the title's de jure counties' holder is "0", don't insert the title
for (const auto& [vassalTitleName, deJureVassal] : landedTitle.getFoundTitles())
{
if (vassalTitleName.find("c_")==0 && titles.count(vassalTitleName) && titles[vassalTitleName]->holder == "0")
if (vassalTitleName.find("c_")==0 && titles.count(vassalTitleName)) // vassalTitle is a valid county
{
toInsert = false;
break;
auto countyHolder = titles[vassalTitleName]->holder;
countyHoldersCache.insert(countyHolder);

// important check: if any of the title's de jure counties' holder is "0", don't insert the title
if (countyHolder == "0")
{
toInsert = false;
break;
}
}
}

if(toInsert)
{
auto vanillaTitle = std::make_shared<Title>();
vanillaTitle->titleName = name;
if (titlesHistory.currentHolderIdMap[name]) vanillaTitle->holder = *titlesHistory.currentHolderIdMap[name];
auto vanillaHistory = titlesHistory.popTitleHistory(name);
if (vanillaHistory) vanillaTitle->historyString = *vanillaHistory;
titles.insert(std::pair(name, vanillaTitle));
Expand All @@ -302,6 +311,22 @@ void CK3::World::insertVanillaNonCountiesToTitles(const ImperatorWorld::World& i
}
}

void CK3::World::removeInvalidLandlessTitles()
{
for (const auto& [name, title] : titles)
{ //important check: if duchy/kingdom/empire title holder holds no county (is landless), remove the title
// this also removes landless titles initialized from Imperator
if (name.find("c_") != 0 && name.find("b_") != 0 && countyHoldersCache.find(title->holder) == countyHoldersCache.end())
{
if (!landedTitles.getFoundTitles().find(name)->second.isLandless()) // does not have landless attribute set to true
{
Log(LogLevel::Info) << "Removing landless title that can't be landless: " << name;
titles.erase(name);
}
}
}
}

void CK3::World::linkSpouses(const ImperatorWorld::World& impWorld)
{
auto counterSpouse = 0;
Expand Down
5 changes: 4 additions & 1 deletion ImperatorToCK3/Source/CK3/CK3World.h
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,15 @@ class World
private:
void importImperatorCharacters(const ImperatorWorld::World& impWorld, bool ConvertBirthAndDeathDates, date endDate);
void importImperatorCharacter(const std::pair<int, std::shared_ptr<ImperatorWorld::Character>>& character, bool ConvertBirthAndDeathDates, date endDate);
void importVanillaNonCountyNonBaronyTitles(const ImperatorWorld::World& impWorld);
void importImperatorCountries(const ImperatorWorld::World& impWorld);
void importImperatorCountry(const std::pair<int, std::shared_ptr<ImperatorWorld::Country>>& country);
void importVanillaProvinces(const std::string& ck3Path);
void importImperatorProvinces(const ImperatorWorld::World& impWorld);
void linkCountiesToTitleHolders(const ImperatorWorld::World& impWorld);
void insertVanillaNonCountiesToTitles(const ImperatorWorld::World& impWorld);
void linkSpouses(const ImperatorWorld::World& impWorld);
void linkMothersAndFathers(const ImperatorWorld::World& impWorld);
void removeInvalidLandlessTitles();

[[nodiscard]] std::optional<std::pair<int, std::shared_ptr<ImperatorWorld::Province>>> determineProvinceSource(const std::vector<int>& impProvinceNumbers,
const ImperatorWorld::World& impWorld) const;
Expand All @@ -60,6 +61,8 @@ class World
TitlesHistory titlesHistory;

LandedTitles landedTitles;

std::set<std::string> countyHoldersCache; // used by removeInvalidLandlessTitles
};

}
Expand Down
43 changes: 42 additions & 1 deletion ImperatorToCK3/Source/CK3/Titles/TitlesHistory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,15 @@ void CK3::TitlesHistory::TitlesHistory::registerKeys()
registerRegex(R"((e|k|d|c|b)_[A-Za-z0-9_\-\']+)", [this](const std::string& titleName, std::istream& theStream) {
const auto historyItem = commonItems::stringOfItem(theStream).getString();
historyMap.insert(std::pair(titleName, historyItem.substr(3, historyItem.size()-4))); // inserts without the opening and closing bracket

std::stringstream tempStream(historyItem);
if (historyItem.find('{') != std::string::npos)
{
const auto titleHistory = TitleHistory(tempStream);
currentHolderIdMap[titleName] = titleHistory.currentHolderEntryWithDate.second.holder;
}
});
registerKeyword(commonItems::catchallRegex, commonItems::ignoreItem);
registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
}

std::optional<std::string> CK3::TitlesHistory::popTitleHistory(const std::string& titleName)
Expand All @@ -42,4 +49,38 @@ std::optional<std::string> CK3::TitlesHistory::popTitleHistory(const std::string
return history;
}
return std::nullopt;
}



CK3::TitleHistory::TitleHistory(std::istream& theStream)
{
registerKeys();
parseStream(theStream);
clearRegisteredKeywords();
}
void CK3::TitleHistory::TitleHistory::registerKeys()
{
registerRegex(R"(\d+[.]\d+[.]\d+)", [this](const std::string& dateStr, std::istream& theStream) {
auto historyEntry = DatedHistoryEntry(theStream);
if (date(dateStr) >= currentHolderEntryWithDate.first && date(dateStr) <= date(867, 1, 1) && historyEntry.holder)
currentHolderEntryWithDate = std::pair(date(dateStr), historyEntry);
});
registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
}



CK3::DatedHistoryEntry::DatedHistoryEntry(std::istream& theStream)
{
registerKeys();
parseStream(theStream);
clearRegisteredKeywords();
}
void CK3::DatedHistoryEntry::DatedHistoryEntry::registerKeys()
{
registerKeyword("holder", [this](const std::string& unused, std::istream& theStream) {
holder = commonItems::singleString(theStream).getString();
});
registerRegex(commonItems::catchallRegex, commonItems::ignoreItem);
}
50 changes: 42 additions & 8 deletions ImperatorToCK3/Source/CK3/Titles/TitlesHistory.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,23 +9,57 @@

namespace CK3
{
class TitlesHistory: commonItems::parser
class DatedHistoryEntry : commonItems::parser
{
/// <summary>
/// This class stores vanilla titles history as strings. To save memory, title's history is removed from the map before being returned.
/// </summary>
public:
/// <summary>
/// This class stores the holder from a single history entry (if there is one).
/// Example entry: 856.1.1 = { holder = akan707 }
/// What's saved in the class: holder = akan707
/// </summary>
public:
DatedHistoryEntry() = default;
explicit DatedHistoryEntry(std::istream& theStream);

std::optional<std::string> holder;

private:
void registerKeys();
}; // class DatedHistoryEntry


class TitleHistory : commonItems::parser
{
/// <summary>
/// This class stores the dated history entries for a single title
/// </summary>
public:
TitleHistory() = default;
explicit TitleHistory(std::istream& theStream);

std::pair<date, DatedHistoryEntry> currentHolderEntryWithDate = { date(1,1,1), DatedHistoryEntry()}; // entry with the closest date <= 867.1.1
private:
void registerKeys();
}; // class TitleHistory


class TitlesHistory : commonItems::parser
{
/// <summary>
/// This class stores vanilla titles history as strings. To save memory, title's history string is removed from the map before being returned.
/// </summary>
public:
TitlesHistory() = default;
explicit TitlesHistory(const Configuration& theConfiguration);
explicit TitlesHistory(const std::string& historyFilePath);

[[nodiscard]] std::optional<std::string> popTitleHistory(const std::string& titleName);
[[nodiscard]] std::optional<std::string> popTitleHistory(const std::string& titleName); // "pop" as from stack, not Imperator Pop ;)
std::map<std::string, std::optional<std::string>> currentHolderIdMap; // value is nullopt only when there is no holder registered before or at CK3 start date

private:
private:
void registerKeys();

std::map<std::string, std::string> historyMap;
};
}; // class TitlesHistory
} // namespace CK3

#endif // CK3_TITLES_HISTORY_H
2 changes: 1 addition & 1 deletion commonItems
Submodule commonItems updated 2 files
+11 −5 Parser.cpp
+3 −0 Parser.h

0 comments on commit 8c78f8f

Please sign in to comment.