Skip to content

Commit

Permalink
Merge pull request #48 from powerof3/46-composable-parsers
Browse files Browse the repository at this point in the history
46 composable parsers
  • Loading branch information
adya authored Apr 13, 2024
2 parents bc627ee + 1b4653e commit 973c030
Show file tree
Hide file tree
Showing 17 changed files with 794 additions and 624 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/maintenance.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
python-version: '3.10'

- name: Run clang-format
run: find -type f \( -name *.h -o -name *.cpp \) | xargs clang-format-14 -style=file -i
run: find -type f \( -name *.h -o -name *.cpp \) | xargs clang-format-15 -style=file -i

- name: Glob files
run: python ${{ github.workspace }}/SPID/ProjectGen.py
Expand Down
1 change: 1 addition & 0 deletions SPID/cmake/headerlist.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,5 @@ set(headers ${headers}
include/LookupNPC.h
include/PCH.h
include/PCLevelMultManager.h
include/Parser.h
)
1 change: 0 additions & 1 deletion SPID/include/DeathDistribution.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ namespace DeathDistribution
///
/// As a result this method configures Manager with discovered valid On Death Distributable Forms.
/// </summary>
/// <param name="dataHandler">A DataHandler that will perform the actual lookup.</param>
void LookupForms(RE::TESDataHandler* const dataHandler);

void LogFormsLookup();
Expand Down
2 changes: 1 addition & 1 deletion SPID/include/Distribute.h
Original file line number Diff line number Diff line change
Expand Up @@ -81,7 +81,7 @@ namespace Distribute
const NPCData& a_npcData,
Forms::DataVec<Form>& forms,
const PCLevelMult::Input& a_input,
std::function<bool(Form*, IndexOrCount)> a_callback,
std::function<void(Form*, IndexOrCount)> a_callback,
DistributedForms* accumulatedForms = nullptr)
{
for (auto& formData : forms) {
Expand Down
4 changes: 2 additions & 2 deletions SPID/include/ExclusiveGroups.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ namespace ExclusiveGroups
std::string name{};

/// Raw filters in RawExclusiveGroup only use NOT and MATCH, there is no meaning for ALL, so it's ignored.
Filters<FormOrEditorID> formIDs{};
Path path{};
RawFormFilters formFilters{};
Path path{};
};

using ExclusiveGroupsVec = std::vector<RawExclusiveGroup>;
Expand Down
17 changes: 9 additions & 8 deletions SPID/include/FormData.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
namespace Forms
{
namespace Lookup

{
struct UnknownPluginException : std::exception
{
Expand Down Expand Up @@ -353,7 +354,7 @@ namespace Forms
}
}

return (options & kRequireAll) == 0 && a_formVec.size() == a_rawFormVec.size();
return (options & kRequireAll) == 0 || a_formVec.size() == a_rawFormVec.size();
}
}

Expand Down Expand Up @@ -434,7 +435,7 @@ namespace Forms
DataVec<Form>& GetForms(bool a_onlyLevelEntries);
DataVec<Form>& GetForms();

void LookupForms(RE::TESDataHandler*, std::string_view a_type, Configs::INI::DataVec&);
void LookupForms(RE::TESDataHandler*, std::string_view a_type, Distribution::INI::DataVec&);
void EmplaceForm(bool isValid, Form*, const IndexOrCount&, const FilterData&, const Path&);

// Init formsWithLevels and formsNoLevels
Expand All @@ -449,7 +450,7 @@ namespace Forms
/// This counter is used for logging purposes.
std::size_t lookupCount{ 0 };

void LookupForm(RE::TESDataHandler*, Configs::INI::Data&);
void LookupForm(RE::TESDataHandler*, Distribution::INI::Data&);
};

inline Distributables<RE::SpellItem> spells{ RECORD::kSpell };
Expand Down Expand Up @@ -492,7 +493,7 @@ namespace Forms
/// <param name="rawForm">A raw form entry that needs to be looked up.</param>
/// <param name="callback">A callback to be called with validated data after successful lookup.</param>
template <class Form = RE::TESForm*>
void LookupGenericForm(RE::TESDataHandler* const dataHandler, Configs::INI::Data& rawForm, std::function<void(bool isValid, Form*, const IndexOrCount&, const FilterData&, const Path& path)> callback);
void LookupGenericForm(RE::TESDataHandler* const dataHandler, Distribution::INI::Data& rawForm, std::function<void(bool isValid, Form*, const IndexOrCount&, const FilterData&, const Path& path)> callback);
}

template <class Form>
Expand Down Expand Up @@ -550,15 +551,15 @@ Forms::DataVec<Form>& Forms::Distributables<Form>::GetForms(bool a_onlyLevelEntr
}

template <class Form>
void Forms::Distributables<Form>::LookupForm(RE::TESDataHandler* dataHandler, Configs::INI::Data& rawForm)
void Forms::Distributables<Form>::LookupForm(RE::TESDataHandler* dataHandler, Distribution::INI::Data& rawForm)
{
Forms::LookupGenericForm<Form>(dataHandler, rawForm, [&](bool isValid, Form* form, const auto& idxOrCount, const auto& filters, const auto& path) {
EmplaceForm(isValid, form, idxOrCount, filters, path);
});
}

template <class Form>
void Forms::Distributables<Form>::LookupForms(RE::TESDataHandler* dataHandler, std::string_view a_type, Configs::INI::DataVec& a_INIDataVec)
void Forms::Distributables<Form>::LookupForms(RE::TESDataHandler* dataHandler, std::string_view a_type, Distribution::INI::DataVec& a_INIDataVec)
{
if (a_INIDataVec.empty()) {
return;
Expand Down Expand Up @@ -606,9 +607,9 @@ void Forms::Distributables<Form>::FinishLookupForms()
}

template <class Form>
void Forms::LookupGenericForm(RE::TESDataHandler* const dataHandler, Configs::INI::Data& rawForm, std::function<void(bool isValid, Form*, const IndexOrCount&, const FilterData&, const Path& path)> callback)
void Forms::LookupGenericForm(RE::TESDataHandler* const dataHandler, Distribution::INI::Data& rawForm, std::function<void(bool isValid, Form*, const IndexOrCount&, const FilterData&, const Path& path)> callback)
{
auto& [formOrEditorID, strings, filterIDs, level, traits, idxOrCount, chance, path] = rawForm;
auto& [type, formOrEditorID, strings, filterIDs, level, traits, idxOrCount, chance, path] = rawForm;

try {
if (auto form = detail::get_form<Form>(dataHandler, formOrEditorID, path, LookupOptions::kCreateIfMissing); form) {
Expand Down
52 changes: 25 additions & 27 deletions SPID/include/LinkedDistribution.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@

namespace LinkedDistribution
{

/// <summary>
/// Scope of a linked form determines which distributions can trigger linked forms.
/// </summary>
Expand Down Expand Up @@ -42,12 +41,16 @@ namespace LinkedDistribution
{
struct RawLinkedForm
{
FormOrEditorID formOrEditorID{};
FormOrEditorID rawForm{};

RECORD::TYPE type{ RECORD::kForm };

Scope scope{ kLocal };

DistributionType distributionType{ kRegular };

/// Raw filters in RawLinkedForm only use MATCH, there is no meaning for ALL or NOT, so they are ignored.
Filters<FormOrEditorID> formIDs{};
RawFormFilters formFilters{};

IndexOrCount idxOrCount{ RandomCount(1, 1) };
PercentChance chance{ 100 };
Expand All @@ -56,9 +59,7 @@ namespace LinkedDistribution
};

using LinkedFormsVec = std::vector<RawLinkedForm>;
using LinkedFormsConfig = std::unordered_map<DistributionType, std::unordered_map<RECORD::TYPE, LinkedFormsVec>>;

inline LinkedFormsConfig linkedForms{};
using LinkedFormsConfig = std::unordered_map<RECORD::TYPE, LinkedFormsVec>;

/// <summary>
/// Checks whether given entry is a linked form and attempts to parse it.
Expand Down Expand Up @@ -92,9 +93,9 @@ namespace LinkedDistribution
type(type)
{}

bool IsEmpty(DistributionType type) const
bool IsEmpty(DistributionType distributionType) const
{
if (const auto it = forms.find(type); it != forms.end()) {
if (const auto it = forms.find(distributionType); it != forms.end()) {
return it->second.empty();
}
return true;
Expand All @@ -103,13 +104,13 @@ namespace LinkedDistribution
RECORD::TYPE GetType() const { return type; }
const FormsMap& GetForms() const { return forms; }

void LookupForms(RE::TESDataHandler* const, DistributionType, INI::LinkedFormsVec& rawLinkedForms);
void LookupForms(RE::TESDataHandler* const, INI::LinkedFormsVec& rawLinkedForms);

private:
RECORD::TYPE type;
FormsMap forms{};

void Link(Form*, Scope, DistributionType, const FormVec& linkedForms, const IndexOrCount&, const PercentChance&, const Path&);
void Link(Form*, Scope, DistributionType, const FormVec& linkedConfigs, const IndexOrCount&, const PercentChance&, const Path&);
};

class Manager : public ISingleton<Manager>
Expand All @@ -120,31 +121,28 @@ namespace LinkedDistribution
///
/// As a result this method configures Manager with discovered valid linked forms.
/// </summary>
/// <param name="dataHandler">A DataHandler that will perform the actual lookup.</param>
/// <param name="rawLinkedDistribution">A raw linked form entries that should be processed.</param>
void LookupLinkedForms(RE::TESDataHandler* const, INI::LinkedFormsConfig& rawLinkedForms = INI::linkedForms);
void LookupLinkedForms(RE::TESDataHandler* const);

void LogLinkedFormsLookup();

bool IsEmpty(DistributionType) const;

/// <summary>
/// Calculates DistributionSet for each linked form and calls a callback for each of them.
/// </summary>
/// <param name="distributionType">Type of the distribution for which linked sets should be returned.</param>
/// <param name="linkedForms">A set of forms for which distribution sets should be calculated.
/// This is typically distributed forms accumulated during first distribution pass.</param>
/// <param name="distribute">A callback to be called with each DistributionSet. This is supposed to do the actual distribution.</param>
void ForEachLinkedDistributionSet(DistributionType, const DistributedForms& linkedForms, std::function<void(DistributionSet&)> distribute);

bool IsEmpty(DistributionType) const;
void ForEachLinkedDistributionSet(DistributionType, const DistributedForms& linkedConfigs, std::function<void(DistributionSet&)> distribute);

private:
template <class Form>
DataVec<Form>& LinkedFormsForForm(DistributionType, const DistributedForm&, Scope, LinkedForms<Form>&) const;

void LookupLinkedForms(RE::TESDataHandler* const, DistributionType, INI::LinkedFormsConfig& rawLinkedForms);
void LogLinkedFormsLookup(DistributionType);

void ForEachLinkedDistributionSet(DistributionType, const DistributedForms& linkedForms, Scope, std::function<void(DistributionSet&)> distribute);
void ForEachLinkedDistributionSet(DistributionType, const DistributedForms& linkedConfigs, Scope, std::function<void(DistributionSet&)> distribute);

LinkedForms<RE::SpellItem> spells{ RECORD::kSpell };
LinkedForms<RE::BGSPerk> perks{ RECORD::kPerk };
Expand Down Expand Up @@ -173,7 +171,7 @@ namespace LinkedDistribution
using namespace Forms::Lookup;

try {
return Forms::detail::get_form<Form>(dataHandler, rawForm.formOrEditorID, rawForm.path, LookupOptions::kCreateIfMissing);
return Forms::detail::get_form<Form>(dataHandler, rawForm.rawForm, rawForm.path, LookupOptions::kCreateIfMissing);
} catch (const UnknownFormIDException& e) {
buffered_logger::error("\t\t[{}] LinkedForm [0x{:X}] ({}) SKIP - formID doesn't exist", e.path, e.formID, e.modName.value_or(""));
} catch (const UnknownPluginException& e) {
Expand Down Expand Up @@ -215,9 +213,9 @@ namespace LinkedDistribution
}

template <class Form>
DataVec<Form>& Manager::LinkedFormsForForm(DistributionType type, const DistributedForm& form, Scope scope, LinkedForms<Form>& linkedForms) const
DataVec<Form>& Manager::LinkedFormsForForm(DistributionType type, const DistributedForm& form, Scope scope, LinkedForms<Form>& linkedConfigs) const
{
auto& forms = linkedForms.forms[type];
auto& forms = linkedConfigs.forms[type];
if (const auto formsIt = forms.find(scope == kLocal ? form.second : ""); formsIt != forms.end()) {
if (const auto linkedFormsIt = formsIt->second.find(form.first); linkedFormsIt != formsIt->second.end()) {
return linkedFormsIt->second;
Expand Down Expand Up @@ -245,25 +243,25 @@ namespace LinkedDistribution
}

template <class Form>
void LinkedForms<Form>::LookupForms(RE::TESDataHandler* const dataHandler, DistributionType type, INI::LinkedFormsVec& rawLinkedForms)
void LinkedForms<Form>::LookupForms(RE::TESDataHandler* const dataHandler, INI::LinkedFormsVec& rawLinkedForms)
{
for (auto& rawForm : rawLinkedForms) {
if (auto form = detail::LookupLinkedForm<Form>(dataHandler, rawForm); form) {
auto& [formID, scope, parentFormIDs, count, chance, path] = rawForm;
auto& [formID, type, scope, distributionType, parentFormIDs, count, chance, path] = rawForm;
FormVec parentForms{};
if (Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, LookupOptions::kNone)) {
Link(form, scope, type, parentForms, count, chance, path);
Link(form, scope, distributionType, parentForms, count, chance, path);
}
}
}
}

template <class Form>
void LinkedForms<Form>::Link(Form* form, Scope scope, DistributionType type, const FormVec& linkedForms, const IndexOrCount& idxOrCount, const PercentChance& chance, const Path& path)
void LinkedForms<Form>::Link(Form* form, Scope scope, DistributionType distributionType, const FormVec& linkedConfigs, const IndexOrCount& idxOrCount, const PercentChance& chance, const Path& path)
{
for (const auto& linkedForm : linkedForms) {
for (const auto& linkedForm : linkedConfigs) {
if (std::holds_alternative<RE::TESForm*>(linkedForm)) {
auto& distributableFormsAtPath = forms[type][scope == kLocal ? path : ""]; // If item is global, we put it in a common map with no information about the path.
auto& distributableFormsAtPath = forms[distributionType][scope == kLocal ? path : ""]; // If item is global, we put it in a common map with no information about the path.
auto& distributableForms = distributableFormsAtPath[std::get<RE::TESForm*>(linkedForm)];
// Note that we don't use Data.index here, as these linked forms don't have any leveled filters
// and as such do not to track their index.
Expand Down
Loading

0 comments on commit 973c030

Please sign in to comment.