Skip to content

Commit

Permalink
Fixed unknown EditorIDs in FormFilters were interpreted as keywords t…
Browse files Browse the repository at this point in the history
…hat needed to be created.
  • Loading branch information
adya committed Apr 9, 2024
1 parent fee13e9 commit 94e67b4
Show file tree
Hide file tree
Showing 4 changed files with 33 additions and 20 deletions.
41 changes: 27 additions & 14 deletions SPID/include/FormData.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ namespace Forms
};
}

enum LookupOptions : std::uint8_t
{
kNone = 0,
kWhitelistedOnly = 1,
kRequireAll = 1 << 1,
kCreateIfMissing = 1 << 2
};

namespace detail
{
using namespace Lookup;
Expand Down Expand Up @@ -140,7 +148,7 @@ namespace Forms
}

template <class Form = RE::TESForm>
std::variant<Form*, const RE::TESFile*> get_form_or_mod(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path, bool whitelistedOnly = false)
std::variant<Form*, const RE::TESFile*> get_form_or_mod(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path, const LookupOptions options)
{
Form* form = nullptr;
const RE::TESFile* mod = nullptr;
Expand Down Expand Up @@ -171,7 +179,7 @@ namespace Forms
} else {
throw KeywordNotFoundException(editorID, false, path);
}
} else {
} else if (options & kCreateIfMissing) {
const auto factory = RE::IFormFactory::GetConcreteFormFactoryByType<RE::BGSKeyword>();
if (auto keyword = factory ? factory->Create() : nullptr; keyword) {
keyword->formEditorID = editorID;
Expand All @@ -181,6 +189,9 @@ namespace Forms
} else {
throw KeywordNotFoundException(editorID, true, path);
}
} else {
// If creating keyword from this editorID is not allowed, then we simply fail as unknown editorID
throw UnknownEditorIDException(editorID, path);
}
};

Expand Down Expand Up @@ -241,6 +252,8 @@ namespace Forms
throw MismatchingFormTypeException(anyForm->GetFormType(), Form::FORMTYPE, editorID, path);
}
} else {
// If template's Form is a generic TESForm, that means caller doesn't request specific form type,
// as such we'll attempt to create a keyword if options allow it.
if constexpr (std::is_same_v<Form, RE::TESForm>) {
form = find_or_create_keyword(editorID);
} else {
Expand All @@ -255,7 +268,7 @@ namespace Forms
return mod;
}

if (whitelistedOnly && form) {
if (options & kWhitelistedOnly && form) {
const auto formType = form->GetFormType();
if (FormType::GetWhitelisted(formType)) {
return form;
Expand All @@ -267,9 +280,9 @@ namespace Forms
return form;
}

inline const RE::TESFile* get_file(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path)
inline const RE::TESFile* get_file(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path, const LookupOptions options)
{
auto formOrMod = get_form_or_mod(dataHandler, formOrEditorID, path);
auto formOrMod = get_form_or_mod(dataHandler, formOrEditorID, path, options);

if (std::holds_alternative<const RE::TESFile*>(formOrMod)) {
return std::get<const RE::TESFile*>(formOrMod);
Expand All @@ -279,9 +292,9 @@ namespace Forms
}

template <class Form = RE::TESForm>
Form* get_form(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path, bool whitelistedOnly = false)
Form* get_form(RE::TESDataHandler* const dataHandler, const FormOrEditorID& formOrEditorID, const Path& path, const LookupOptions options)
{
auto formOrMod = get_form_or_mod<Form>(dataHandler, formOrEditorID, path, whitelistedOnly);
auto formOrMod = get_form_or_mod<Form>(dataHandler, formOrEditorID, path, options);

if (std::holds_alternative<Form*>(formOrMod)) {
return std::get<Form*>(formOrMod);
Expand All @@ -290,15 +303,15 @@ namespace Forms
return nullptr;
}

inline bool formID_to_form(RE::TESDataHandler* const a_dataHandler, RawFormVec& a_rawFormVec, FormVec& a_formVec, const Path& a_path, bool a_all = false, bool whitelistedOnly = true)
inline bool formID_to_form(RE::TESDataHandler* const a_dataHandler, RawFormVec& a_rawFormVec, FormVec& a_formVec, const Path& a_path, LookupOptions options)
{
if (a_rawFormVec.empty()) {
return true;
}

for (auto& formOrEditorID : a_rawFormVec) {
try {
auto form = get_form_or_mod(a_dataHandler, formOrEditorID, a_path, whitelistedOnly);
auto form = get_form_or_mod(a_dataHandler, formOrEditorID, a_path, options);
a_formVec.emplace_back(form);
} catch (const UnknownFormIDException& e) {
buffered_logger::error("\t\t[{}] Filter [0x{:X}] ({}) SKIP - formID doesn't exist", e.path, e.formID, e.modName.value_or(""));
Expand Down Expand Up @@ -340,7 +353,7 @@ namespace Forms
}
}

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

Expand Down Expand Up @@ -601,15 +614,15 @@ void Forms::LookupGenericForm(RE::TESDataHandler* const dataHandler, INI::Data&
auto& [formOrEditorID, strings, filterIDs, level, traits, idxOrCount, chance, path] = rawForm;

try {
if (auto form = detail::get_form<Form>(dataHandler, formOrEditorID, path); form) {
if (auto form = detail::get_form<Form>(dataHandler, formOrEditorID, path, LookupOptions::kCreateIfMissing); form) {
FormFilters filterForms{};

bool validEntry = detail::formID_to_form(dataHandler, filterIDs.ALL, filterForms.ALL, path, true);
bool validEntry = detail::formID_to_form(dataHandler, filterIDs.ALL, filterForms.ALL, path, LookupOptions::kRequireAll);
if (validEntry) {
validEntry = detail::formID_to_form(dataHandler, filterIDs.NOT, filterForms.NOT, path);
validEntry = detail::formID_to_form(dataHandler, filterIDs.NOT, filterForms.NOT, path, LookupOptions::kWhitelistedOnly);
}
if (validEntry) {
validEntry = detail::formID_to_form(dataHandler, filterIDs.MATCH, filterForms.MATCH, path);
validEntry = detail::formID_to_form(dataHandler, filterIDs.MATCH, filterForms.MATCH, path, LookupOptions::kWhitelistedOnly);
}

FilterData filters{ strings, filterForms, level, traits, chance };
Expand Down
4 changes: 2 additions & 2 deletions SPID/include/LinkedDistribution.h
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ namespace LinkedDistribution
using namespace Forms::Lookup;

try {
return Forms::detail::get_form<Form>(dataHandler, rawForm.formOrEditorID, rawForm.path);
return Forms::detail::get_form<Form>(dataHandler, rawForm.formOrEditorID, 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 @@ -232,7 +232,7 @@ namespace LinkedDistribution
if (auto form = detail::LookupLinkedForm<Form>(dataHandler, rawForm); form) {
auto& [formID, scope, parentFormIDs, count, chance, path] = rawForm;
FormVec parentForms{};
if (Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, false, false)) {
if (Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, LookupOptions::kNone)) {
Link(form, scope, parentForms, count, chance, path);
}
}
Expand Down
4 changes: 2 additions & 2 deletions SPID/src/ExclusiveGroups.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,8 @@ namespace ExclusiveGroups
FormVec match{};
FormVec formsNot{};

if (Forms::detail::formID_to_form(dataHandler, filterIDs.MATCH, match, path, false, false) &&
Forms::detail::formID_to_form(dataHandler, filterIDs.NOT, formsNot, path, false, false)) {
if (Forms::detail::formID_to_form(dataHandler, filterIDs.MATCH, match, path, Forms::LookupOptions::kNone) &&
Forms::detail::formID_to_form(dataHandler, filterIDs.NOT, formsNot, path, Forms::LookupOptions::kNone)) {
for (const auto& form : match) {
if (std::holds_alternative<RE::TESForm*>(form)) {
forms.insert(std::get<RE::TESForm*>(form));
Expand Down
4 changes: 2 additions & 2 deletions SPID/src/LinkedDistribution.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ namespace LinkedDistribution
if (auto form = detail::LookupLinkedForm(dataHandler, rawSpell); form) {
auto& [formID, scope, parentFormIDs, idxOrCount, chance, path] = rawSpell;
FormVec parentForms{};
if (!Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, false, false)) {
if (!Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, LookupOptions::kNone)) {
continue;
}
if (const auto spell = form->As<RE::SpellItem>(); spell) {
Expand All @@ -141,7 +141,7 @@ namespace LinkedDistribution
if (auto form = detail::LookupLinkedForm(dataHandler, rawForm); form) {
auto& [formID, scope, parentFormIDs, idxOrCount, chance, path] = rawForm;
FormVec parentForms{};
if (!Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, false, false)) {
if (!Forms::detail::formID_to_form(dataHandler, parentFormIDs.MATCH, parentForms, path, LookupOptions::kNone)) {
continue;
}
// Add to appropriate list. (Note that type inferring doesn't recognize SleepOutfit, Skin or DeathItems)
Expand Down

0 comments on commit 94e67b4

Please sign in to comment.