Skip to content

Commit

Permalink
code cleanup
Browse files Browse the repository at this point in the history
  • Loading branch information
powerof3 committed Nov 11, 2022
1 parent 8b20723 commit d7822f5
Show file tree
Hide file tree
Showing 8 changed files with 149 additions and 154 deletions.
7 changes: 2 additions & 5 deletions SPID/include/DistributePCLevelMult.h
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
#pragma once

namespace Distribute
namespace Distribute::PlayerLeveledActor
{
namespace PlayerLeveledActor
{
void Install();
}
void Install();
}
2 changes: 1 addition & 1 deletion SPID/include/LookupFilters.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,5 @@ namespace Filter

bool forms(RE::TESNPC& a_actorbase, const FormFilters& a_formFilters);

SECONDARY_RESULT secondary(const RE::TESNPC& a_actorbase, const LevelFilters& a_levelFilters, const Traits& a_traits, float chance, bool a_noPlayerLevelDistribution);
SECONDARY_RESULT secondary(const RE::TESNPC& a_actorbase, const LevelFilters& a_levelFilters, const Traits& a_traits, float a_chance, bool a_noPlayerLevelDistribution);
}
2 changes: 1 addition & 1 deletion SPID/include/LookupForms.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ namespace Lookup
a_formID.emplace(mergedFormID);
}
const std::string mergedModString{ mergedModName };
if (!(a_modName.value_or("").empty()) && !mergedModString.empty() && a_modName.value_or("") != mergedModString) {
if (!a_modName.value_or("").empty() && !mergedModString.empty() && a_modName.value_or("") != mergedModString) {
if (conversion_log.empty()) {
conversion_log = std::format("{}->{}", a_modName.value_or(""), mergedModString);
} else {
Expand Down
18 changes: 9 additions & 9 deletions SPID/include/PCLevelMultManager.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,20 +66,20 @@ namespace PCLevelMult
kHit
};

struct Entries
{
std::map<RE::FormID, std::set<std::uint32_t>> rejectedEntries{}; // Distributed formID, FormData vector index
std::set<std::pair<RE::FormID, IdxOrCount>> distributedEntries{}; // Distributed formID, distributed count/idx
};

struct Data
{
LEVEL_CAP_STATE levelCapState{};
struct Entries
{
std::unordered_map<RE::FormID, std::set<std::uint32_t>> rejectedEntries{}; // Distributed formID, FormData vector index
std::set<std::pair<RE::FormID, IdxOrCount>> distributedEntries{}; // Distributed formID, distributed count/idx
};

LEVEL_CAP_STATE levelCapState{};
std::map<std::uint16_t, Entries> entries{}; // Actor Level, Entries
};

std::map<std::uint64_t, // PlayerID
std::map<RE::FormID, Data>> // NPC formID, Data
std::unordered_map<std::uint64_t, // PlayerID
std::unordered_map<RE::FormID, Data>> // NPC formID, Data
cache{};

std::uint64_t currentPlayerID{ 0 };
Expand Down
2 changes: 1 addition & 1 deletion SPID/src/Cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ namespace Cache
if (function) {
return function(a_formID);
}
return std::string();
return {};
}

bool FormType::GetWhitelisted(const RE::FormType a_type)
Expand Down
263 changes: 130 additions & 133 deletions SPID/src/DistributePCLevelMult.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,145 +2,142 @@
#include "Distribute.h"
#include "PCLevelMultManager.h"

namespace Distribute
namespace Distribute::PlayerLeveledActor
{
namespace PlayerLeveledActor
{
struct HandleUpdatePlayerLevel
{
static void thunk(RE::Actor* a_actor)
{
if (const auto npc = a_actor->GetActorBase(); npc && npc->HasPCLevelMult()) {
const auto input = npc->IsDynamicForm() ? PCLevelMult::Input{ a_actor, npc, true, false } : // use character formID for permanent storage
PCLevelMult::Input{ npc, true, false };
Distribute(npc, input);
}
struct HandleUpdatePlayerLevel
{
static void thunk(RE::Actor* a_actor)
{
if (const auto npc = a_actor->GetActorBase(); npc && npc->HasPCLevelMult()) {
const auto input = npc->IsDynamicForm() ? PCLevelMult::Input{ a_actor, npc, true, false } : // use character formID for permanent storage
PCLevelMult::Input{ npc, true, false };
Distribute(npc, input);
}

func(a_actor);
}
static inline REL::Relocation<decltype(thunk)> func;
};
func(a_actor);
}
static inline REL::Relocation<decltype(thunk)> func;
};

struct LoadGame
{
static void thunk(RE::Character* a_this, std::uintptr_t a_buf)
{
if (const auto actorbase = a_this->GetActorBase(); actorbase && actorbase->HasPCLevelMult()) {
const auto input = actorbase->IsDynamicForm() ? PCLevelMult::Input{ a_this, actorbase, true, false } : // use character formID for permanent storage
PCLevelMult::Input{ actorbase, true, false };
struct LoadGame
{
static void thunk(RE::Character* a_this, std::uintptr_t a_buf)
{
if (const auto actorbase = a_this->GetActorBase(); actorbase && actorbase->HasPCLevelMult()) {
const auto input = actorbase->IsDynamicForm() ? PCLevelMult::Input{ a_this, actorbase, true, false } : // use character formID for permanent storage
PCLevelMult::Input{ actorbase, true, false };

if (const auto pcLevelMultManager = PCLevelMult::Manager::GetSingleton(); !pcLevelMultManager->FindDistributedEntry(input)) {
//start distribution for first time
Distribute(actorbase, input);
} else {
//handle redistribution and removal
pcLevelMultManager->ForEachDistributedEntry(input, [&](RE::TESForm& a_form, [[maybe_unused]] IdxOrCount a_count, bool a_isBelowLevel) {
switch (a_form.GetFormType()) {
case RE::FormType::Keyword:
{
auto keyword = a_form.As<RE::BGSKeyword>();
if (a_isBelowLevel) {
actorbase->RemoveKeyword(keyword);
} else {
actorbase->AddKeyword(keyword);
}
}
break;
case RE::FormType::Faction:
{
auto faction = a_form.As<RE::TESFaction>();
auto it = std::ranges::find_if(actorbase->factions, [&](const auto& factionRank) {
return factionRank.faction == faction;
});
if (it != actorbase->factions.end()) {
if (a_isBelowLevel) {
(*it).rank = -1;
} else {
(*it).rank = 1;
}
}
}
break;
case RE::FormType::Perk:
{
auto perk = a_form.As<RE::BGSPerk>();
if (a_isBelowLevel) {
actorbase->RemovePerk(perk);
} else {
actorbase->AddPerk(perk, 1);
}
}
break;
case RE::FormType::Spell:
{
auto spell = a_form.As<RE::SpellItem>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveSpell(spell);
} else if (!actorEffects->GetIndex(spell)) {
actorEffects->AddSpell(spell);
}
}
}
break;
case RE::FormType::LeveledSpell:
{
auto spell = a_form.As<RE::TESLevSpell>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveLevSpell(spell);
} else {
actorEffects->AddLevSpell(spell);
}
}
}
break;
case RE::FormType::Shout:
{
auto shout = a_form.As<RE::TESShout>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveShout(shout);
} else {
actorEffects->AddShout(shout);
}
}
}
break;
default:
{
if (a_form.IsInventoryObject()) {
auto boundObject = static_cast<RE::TESBoundObject*>(&a_form);
if (a_isBelowLevel) {
actorbase->RemoveObjectFromContainer(boundObject, a_count);
} else if (actorbase->CountObjectsInContainer(boundObject) < a_count) {
actorbase->AddObjectToContainer(boundObject, a_count, a_this);
}
}
}
break;
}
});
}
}
if (const auto pcLevelMultManager = PCLevelMult::Manager::GetSingleton(); !pcLevelMultManager->FindDistributedEntry(input)) {
//start distribution for first time
Distribute(actorbase, input);
} else {
//handle redistribution and removal
pcLevelMultManager->ForEachDistributedEntry(input, [&](RE::TESForm& a_form, [[maybe_unused]] IdxOrCount a_count, bool a_isBelowLevel) {
switch (a_form.GetFormType()) {
case RE::FormType::Keyword:
{
auto keyword = a_form.As<RE::BGSKeyword>();
if (a_isBelowLevel) {
actorbase->RemoveKeyword(keyword);
} else {
actorbase->AddKeyword(keyword);
}
}
break;
case RE::FormType::Faction:
{
auto faction = a_form.As<RE::TESFaction>();
auto it = std::ranges::find_if(actorbase->factions, [&](const auto& factionRank) {
return factionRank.faction == faction;
});
if (it != actorbase->factions.end()) {
if (a_isBelowLevel) {
(*it).rank = -1;
} else {
(*it).rank = 1;
}
}
}
break;
case RE::FormType::Perk:
{
auto perk = a_form.As<RE::BGSPerk>();
if (a_isBelowLevel) {
actorbase->RemovePerk(perk);
} else {
actorbase->AddPerk(perk, 1);
}
}
break;
case RE::FormType::Spell:
{
auto spell = a_form.As<RE::SpellItem>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveSpell(spell);
} else if (!actorEffects->GetIndex(spell)) {
actorEffects->AddSpell(spell);
}
}
}
break;
case RE::FormType::LeveledSpell:
{
auto spell = a_form.As<RE::TESLevSpell>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveLevSpell(spell);
} else {
actorEffects->AddLevSpell(spell);
}
}
}
break;
case RE::FormType::Shout:
{
auto shout = a_form.As<RE::TESShout>();
if (auto actorEffects = actorbase->GetSpellList()) {
if (a_isBelowLevel) {
actorEffects->RemoveShout(shout);
} else {
actorEffects->AddShout(shout);
}
}
}
break;
default:
{
if (a_form.IsInventoryObject()) {
auto boundObject = static_cast<RE::TESBoundObject*>(&a_form);
if (a_isBelowLevel) {
actorbase->RemoveObjectFromContainer(boundObject, a_count);
} else if (actorbase->CountObjectsInContainer(boundObject) < a_count) {
actorbase->AddObjectToContainer(boundObject, a_count, a_this);
}
}
}
break;
}
});
}
}

func(a_this, a_buf);
}
static inline REL::Relocation<decltype(thunk)> func;
func(a_this, a_buf);
}
static inline REL::Relocation<decltype(thunk)> func;

static inline size_t index{ 0 };
static inline size_t size{ 0xF };
};
static inline size_t index{ 0 };
static inline size_t size{ 0xF };
};

void Install()
{
// ProcessLists::HandleUpdate
// inlined into SetLevel in AE
REL::Relocation<std::uintptr_t> target{ RELOCATION_ID(40575, 41567), OFFSET(0x86, 0x137) };
stl::write_thunk_call<HandleUpdatePlayerLevel>(target.address());
void Install()
{
// ProcessLists::HandleUpdate
// inlined into SetLevel in AE
REL::Relocation<std::uintptr_t> target{ RELOCATION_ID(40575, 41567), OFFSET(0x86, 0x137) };
stl::write_thunk_call<HandleUpdatePlayerLevel>(target.address());

stl::write_vfunc<RE::Character, LoadGame>();
logger::info(" Hooked npc load save");
}
}
stl::write_vfunc<RE::Character, LoadGame>();
logger::info(" Hooked npc load save");
}
}
6 changes: 3 additions & 3 deletions SPID/src/KeywordDependencies.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -158,9 +158,9 @@ void Dependencies::ResolveKeywords()
addDependencies(strings_NOT, findKeyword);
addDependencies(strings_MATCH, findKeyword);
addDependencies(strings_ANY, [&](const std::string& name) -> RE::BGSKeyword* {
for (const auto& iter : allKeywords) {
if (string::icontains(iter.first, name)) {
return iter.second;
for (const auto& [keywordName, keyword] : allKeywords) {
if (string::icontains(keywordName, name)) {
return keyword;
}
}
return nullptr;
Expand Down
3 changes: 2 additions & 1 deletion SPID/src/PCLevelMultManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,8 @@ namespace PCLevelMult
}
}

void Manager::DeleteNPC(RE::FormID a_characterID)
// For spawned actors with FF reference IDs
void Manager::DeleteNPC(RE::FormID a_characterID)
{
auto& currentCache = cache[GetSingleton()->GetCurrentPlayerID()];
if (const auto it = currentCache.find(a_characterID); it != currentCache.end()) {
Expand Down

0 comments on commit d7822f5

Please sign in to comment.