Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| f2d1d26137 | |||
| 0089f06a27 | |||
| bd4d2a5f88 | |||
| f410fb3cfb | |||
| ef0ce50833 | |||
| 2ae83c9b7c | |||
| 4919e92157 | |||
| 654067f863 | |||
| ae35ac9fbb | |||
| c01fbe9265 | |||
| 4220779b99 | |||
| 29f7c4e566 | |||
| 3a52cb85b1 | |||
| 946e05d1ed | |||
| c7c9017ce8 | |||
| 34046f60db | |||
| ea079eafae | |||
| deaac1c723 | |||
| 1fedd07be1 | |||
| 3c2a2343aa |
@ -16,5 +16,14 @@ Keyword = ETR_NotArtifact|Armor|TGMark,WAF_ClothingPouch
|
||||
; Exclude CCOR/CACO filter keyword
|
||||
Keyword = ETR_NotArtifact|Misc Item|TGMark,NoCraftingExperience,-VendorItemGem
|
||||
|
||||
; Include Amulets of Skyrim
|
||||
; Include Amulets of Skyrim (unenchanted clothing and jewelry are excluded in Artifact Tracker_KID.ini)
|
||||
Keyword = ETR_ExtraArtifact|Armor|TGMark,SL01AmuletsSkyrim.esp
|
||||
|
||||
; Exclude Hendraheim clutter
|
||||
Keyword = ETR_NotArtifact|Misc Item|cceejsse004-hall.esl,TGMark
|
||||
|
||||
; CACO pond fish - get the CACO+Fishing CC patch from kryptopyr's Patch Hub
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|TGMark,0x33F5D5~Complete Alchemy & Cooking Overhaul.esp,0x32608D~Complete Alchemy & Cooking Overhaul.esp,0x33F5DC~Complete Alchemy & Cooking Overhaul.esp,0x33F5DA~Complete Alchemy & Cooking Overhaul.esp,0x3302A5~Complete Alchemy & Cooking Overhaul.esp,0x3302AA~Complete Alchemy & Cooking Overhaul.esp,0x33A4D2~Complete Alchemy & Cooking Overhaul.esp,0x33F5D7~Complete Alchemy & Cooking Overhaul.esp,0x32608F~Complete Alchemy & Cooking Overhaul.esp,0x3302A6~Complete Alchemy & Cooking Overhaul.esp,0x3353B6~Complete Alchemy & Cooking Overhaul.esp,0x33F5D9~Complete Alchemy & Cooking Overhaul.esp,0x326087~Complete Alchemy & Cooking Overhaul.esp,0x3353B0~Complete Alchemy & Cooking Overhaul.esp,0x32609E~Complete Alchemy & Cooking Overhaul.esp,0x32608E~Complete Alchemy & Cooking Overhaul.esp
|
||||
|
||||
; CACO salmon
|
||||
Keyword = ETR_ExtraArtifact|Potion|TGMark,0xCCA147~Update.esm,0xCCA148~Update.esm
|
||||
|
||||
Binary file not shown.
@ -1,2 +1,2 @@
|
||||
[InternetShortcut]
|
||||
URL=https://eddoursul.win/mods/artifact-tracker/
|
||||
URL=https://mod.pub/skyrim-se/36-artifact-tracker
|
||||
|
||||
@ -52,6 +52,9 @@ Keyword = ETR_NotArtifact|Weapon|WeapTypeStaff|-E
|
||||
; Exclude unenchanted clothes
|
||||
Keyword = ETR_NotArtifact|Armor||-E,CLOTHING
|
||||
|
||||
; Pond fish
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|0x106E1C,0x106E1B,0x106E1A,0x106E19,0x106E18
|
||||
|
||||
; Free Creation Club mods
|
||||
Keyword = ETR_ExtraArtifact|Potion|TGMark,0x88B~ccBGSSSE001-Fish.esm,0x890~ccBGSSSE001-Fish.esm,0x891~ccBGSSSE001-Fish.esm,0x896~ccBGSSSE001-Fish.esm,0x897~ccBGSSSE001-Fish.esm,0x898~ccBGSSSE001-Fish.esm,0x89B~ccBGSSSE001-Fish.esm,0x89C~ccBGSSSE001-Fish.esm,0x89E~ccBGSSSE001-Fish.esm,0x8A0~ccBGSSSE001-Fish.esm,0x8A1~ccBGSSSE001-Fish.esm,0x8A2~ccBGSSSE001-Fish.esm,0x8A3~ccBGSSSE001-Fish.esm,0x8A4~ccBGSSSE001-Fish.esm,0xF25~ccBGSSSE001-Fish.esm
|
||||
Keyword = ETR_ExtraArtifact|Ingredient|ccBGSSSE001-Fish.esm,TGMark
|
||||
|
||||
165
LICENSE.txt
165
LICENSE.txt
@ -1,165 +0,0 @@
|
||||
GNU LESSER GENERAL PUBLIC LICENSE
|
||||
Version 3, 29 June 2007
|
||||
|
||||
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
|
||||
Everyone is permitted to copy and distribute verbatim copies
|
||||
of this license document, but changing it is not allowed.
|
||||
|
||||
|
||||
This version of the GNU Lesser General Public License incorporates
|
||||
the terms and conditions of version 3 of the GNU General Public
|
||||
License, supplemented by the additional permissions listed below.
|
||||
|
||||
0. Additional Definitions.
|
||||
|
||||
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||
General Public License.
|
||||
|
||||
"The Library" refers to a covered work governed by this License,
|
||||
other than an Application or a Combined Work as defined below.
|
||||
|
||||
An "Application" is any work that makes use of an interface provided
|
||||
by the Library, but which is not otherwise based on the Library.
|
||||
Defining a subclass of a class defined by the Library is deemed a mode
|
||||
of using an interface provided by the Library.
|
||||
|
||||
A "Combined Work" is a work produced by combining or linking an
|
||||
Application with the Library. The particular version of the Library
|
||||
with which the Combined Work was made is also called the "Linked
|
||||
Version".
|
||||
|
||||
The "Minimal Corresponding Source" for a Combined Work means the
|
||||
Corresponding Source for the Combined Work, excluding any source code
|
||||
for portions of the Combined Work that, considered in isolation, are
|
||||
based on the Application, and not on the Linked Version.
|
||||
|
||||
The "Corresponding Application Code" for a Combined Work means the
|
||||
object code and/or source code for the Application, including any data
|
||||
and utility programs needed for reproducing the Combined Work from the
|
||||
Application, but excluding the System Libraries of the Combined Work.
|
||||
|
||||
1. Exception to Section 3 of the GNU GPL.
|
||||
|
||||
You may convey a covered work under sections 3 and 4 of this License
|
||||
without being bound by section 3 of the GNU GPL.
|
||||
|
||||
2. Conveying Modified Versions.
|
||||
|
||||
If you modify a copy of the Library, and, in your modifications, a
|
||||
facility refers to a function or data to be supplied by an Application
|
||||
that uses the facility (other than as an argument passed when the
|
||||
facility is invoked), then you may convey a copy of the modified
|
||||
version:
|
||||
|
||||
a) under this License, provided that you make a good faith effort to
|
||||
ensure that, in the event an Application does not supply the
|
||||
function or data, the facility still operates, and performs
|
||||
whatever part of its purpose remains meaningful, or
|
||||
|
||||
b) under the GNU GPL, with none of the additional permissions of
|
||||
this License applicable to that copy.
|
||||
|
||||
3. Object Code Incorporating Material from Library Header Files.
|
||||
|
||||
The object code form of an Application may incorporate material from
|
||||
a header file that is part of the Library. You may convey such object
|
||||
code under terms of your choice, provided that, if the incorporated
|
||||
material is not limited to numerical parameters, data structure
|
||||
layouts and accessors, or small macros, inline functions and templates
|
||||
(ten or fewer lines in length), you do both of the following:
|
||||
|
||||
a) Give prominent notice with each copy of the object code that the
|
||||
Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
4. Combined Works.
|
||||
|
||||
You may convey a Combined Work under terms of your choice that,
|
||||
taken together, effectively do not restrict modification of the
|
||||
portions of the Library contained in the Combined Work and reverse
|
||||
engineering for debugging such modifications, if you also do each of
|
||||
the following:
|
||||
|
||||
a) Give prominent notice with each copy of the Combined Work that
|
||||
the Library is used in it and that the Library and its use are
|
||||
covered by this License.
|
||||
|
||||
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||
document.
|
||||
|
||||
c) For a Combined Work that displays copyright notices during
|
||||
execution, include the copyright notice for the Library among
|
||||
these notices, as well as a reference directing the user to the
|
||||
copies of the GNU GPL and this license document.
|
||||
|
||||
d) Do one of the following:
|
||||
|
||||
0) Convey the Minimal Corresponding Source under the terms of this
|
||||
License, and the Corresponding Application Code in a form
|
||||
suitable for, and under terms that permit, the user to
|
||||
recombine or relink the Application with a modified version of
|
||||
the Linked Version to produce a modified Combined Work, in the
|
||||
manner specified by section 6 of the GNU GPL for conveying
|
||||
Corresponding Source.
|
||||
|
||||
1) Use a suitable shared library mechanism for linking with the
|
||||
Library. A suitable mechanism is one that (a) uses at run time
|
||||
a copy of the Library already present on the user's computer
|
||||
system, and (b) will operate properly with a modified version
|
||||
of the Library that is interface-compatible with the Linked
|
||||
Version.
|
||||
|
||||
e) Provide Installation Information, but only if you would otherwise
|
||||
be required to provide such information under section 6 of the
|
||||
GNU GPL, and only to the extent that such information is
|
||||
necessary to install and execute a modified version of the
|
||||
Combined Work produced by recombining or relinking the
|
||||
Application with a modified version of the Linked Version. (If
|
||||
you use option 4d0, the Installation Information must accompany
|
||||
the Minimal Corresponding Source and Corresponding Application
|
||||
Code. If you use option 4d1, you must provide the Installation
|
||||
Information in the manner specified by section 6 of the GNU GPL
|
||||
for conveying Corresponding Source.)
|
||||
|
||||
5. Combined Libraries.
|
||||
|
||||
You may place library facilities that are a work based on the
|
||||
Library side by side in a single library together with other library
|
||||
facilities that are not Applications and are not covered by this
|
||||
License, and convey such a combined library under terms of your
|
||||
choice, if you do both of the following:
|
||||
|
||||
a) Accompany the combined library with a copy of the same work based
|
||||
on the Library, uncombined with any other library facilities,
|
||||
conveyed under the terms of this License.
|
||||
|
||||
b) Give prominent notice with the combined library that part of it
|
||||
is a work based on the Library, and explaining where to find the
|
||||
accompanying uncombined form of the same work.
|
||||
|
||||
6. Revised Versions of the GNU Lesser General Public License.
|
||||
|
||||
The Free Software Foundation may publish revised and/or new versions
|
||||
of the GNU Lesser General Public License from time to time. Such new
|
||||
versions will be similar in spirit to the present version, but may
|
||||
differ in detail to address new problems or concerns.
|
||||
|
||||
Each version is given a distinguishing version number. If the
|
||||
Library as you received it specifies that a certain numbered version
|
||||
of the GNU Lesser General Public License "or any later version"
|
||||
applies to it, you have the option of following the terms and
|
||||
conditions either of that published version or of any later version
|
||||
published by the Free Software Foundation. If the Library as you
|
||||
received it does not specify a version number of the GNU Lesser
|
||||
General Public License, you may choose any version of the GNU Lesser
|
||||
General Public License ever published by the Free Software Foundation.
|
||||
|
||||
If the Library as you received it specifies that a proxy can decide
|
||||
whether future versions of the GNU Lesser General Public License shall
|
||||
apply, that proxy's public statement of acceptance of any version is
|
||||
permanent authorization for you to choose that version for the
|
||||
Library.
|
||||
Binary file not shown.
@ -6,7 +6,7 @@ message("Using toolchain file ${CMAKE_TOOLCHAIN_FILE}.")
|
||||
########################################################################################################################
|
||||
project(
|
||||
ArtifactTracker
|
||||
VERSION 1.0.1
|
||||
VERSION 1.0.11
|
||||
DESCRIPTION "Artifact Tracker"
|
||||
LANGUAGES CXX)
|
||||
set(CMAKE_CXX_STANDARD 23)
|
||||
|
||||
@ -21,7 +21,7 @@ BEGIN
|
||||
VALUE "FileDescription", "@PROJECT_DESCRIPTION@"
|
||||
VALUE "FileVersion", "@PROJECT_VERSION@"
|
||||
VALUE "InternalName", "@PROJECT_NAME@"
|
||||
VALUE "LegalCopyright", "GNU Lesser General Public License 3.0"
|
||||
VALUE "LegalCopyright", "ModPub Non-Commercial Private Use License 1.0"
|
||||
VALUE "ProductName", "@PROJECT_FRIENDLY_NAME@"
|
||||
VALUE "ProductVersion", "@PROJECT_VERSION@"
|
||||
VALUE "OriginalFilename", "@PROJECT_NAME@.dll"
|
||||
|
||||
@ -9,10 +9,12 @@ using namespace SKSE::log;
|
||||
namespace ArtifactTracker
|
||||
{
|
||||
bool g_bLoaded = false;
|
||||
bool g_bSaveLoaded = true;
|
||||
bool g_bHomeContainer = false;
|
||||
bool g_bBookShelf = false;
|
||||
bool g_bTakeAll = false;
|
||||
bool g_bNotifyNewArtifact = false;
|
||||
bool g_bWarnMissingMoreHUD = true;
|
||||
std::uint32_t g_bTakeAllCount = 0;
|
||||
std::int32_t g_iFollowerIndex = 0;
|
||||
RE::TESBoundObject* g_cellContainer;
|
||||
@ -23,6 +25,7 @@ namespace ArtifactTracker
|
||||
RE::BGSKeyword* g_homeKeyword;
|
||||
std::unordered_map<RE::FormID, RE::TESForm*> g_artifactMap;
|
||||
std::unordered_set<RE::FormType> g_artifactFormTypes;
|
||||
std::unordered_set<RE::FormType> g_artifactAllFormTypes;
|
||||
std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
|
||||
RE::TESObjectREFR* g_cellStorage;
|
||||
const SKSE::LoadInterface* g_loadInterface;
|
||||
@ -43,7 +46,9 @@ namespace ArtifactTracker
|
||||
|
||||
SKSE::GetModCallbackEventSource()->RemoveEventSink(EventListener::GetSingleton());
|
||||
|
||||
g_cellContainer = dataHandler->LookupForm(0x804, "Artifact Tracker.esp")->As<RE::TESBoundObject>(); // ETR_CellStorageContainer
|
||||
if (const auto& form = dataHandler->LookupForm(0x804, "Artifact Tracker.esp")) {
|
||||
g_cellContainer = form->As<RE::TESBoundObject>(); // ETR_CellStorageContainer
|
||||
}
|
||||
|
||||
g_listNew = dataHandler->LookupForm<RE::BGSListForm>(0x800, "Artifact Tracker.esp"); // ETR_ItemsNew
|
||||
g_listStored = dataHandler->LookupForm<RE::BGSListForm>(0x801, "Artifact Tracker.esp"); // ETR_ItemsStored
|
||||
@ -65,13 +70,27 @@ namespace ArtifactTracker
|
||||
std::map<std::string, bool> settings{
|
||||
{ "DumpItemList", false },
|
||||
{ "NewArtifactNotifications", false },
|
||||
{ "WarnMissingMoreHUD", true },
|
||||
{ "WarnMissingKID", true },
|
||||
};
|
||||
LoadINI(&settings, "Data/SKSE/Plugins/ArtifactTracker.ini");
|
||||
|
||||
g_bNotifyNewArtifact = settings.at("NewArtifactNotifications");
|
||||
g_bWarnMissingMoreHUD = settings.at("WarnMissingMoreHUD");
|
||||
|
||||
// Preloading item lists
|
||||
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Weapon);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Armor);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Book);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Misc);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::AlchemyItem);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Ingredient);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::SoulGem);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Ammo);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::Scroll);
|
||||
g_artifactAllFormTypes.insert(RE::FormType::KeyMaster);
|
||||
|
||||
g_artifactFormTypes.insert(RE::FormType::Weapon);
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::TESObjectWEAP>()) {
|
||||
if (form->GetPlayable() && !form->IsBound() && !form->weaponData.flags.all(RE::TESObjectWEAP::Data::Flag::kCantDrop)) {
|
||||
@ -131,10 +150,40 @@ namespace ArtifactTracker
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::TESAmmo>()) {
|
||||
if (form->GetPlayable() && form->AsKeywordForm()->HasKeyword(extraArtifactKeyword) && !form->AsKeywordForm()->HasKeyword(notArtifactKeyword)) {
|
||||
g_artifactMap[form->formID] = form;
|
||||
g_artifactFormTypes.insert(RE::FormType::Ammo);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::ScrollItem>()) {
|
||||
if (form->HasKeyword(extraArtifactKeyword) && !form->HasKeyword(notArtifactKeyword)) {
|
||||
g_artifactMap[form->formID] = form;
|
||||
g_artifactFormTypes.insert(RE::FormType::Scroll);
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto& form : dataHandler->GetFormArray<RE::TESKey>()) {
|
||||
if (form->HasKeyword(extraArtifactKeyword) && !form->HasKeyword(notArtifactKeyword)) {
|
||||
g_artifactMap[form->formID] = form;
|
||||
g_artifactFormTypes.insert(RE::FormType::KeyMaster);
|
||||
}
|
||||
}
|
||||
|
||||
EventListener::Install();
|
||||
OnGameLoad(); // covers new game and coc'ing from the main menu
|
||||
|
||||
g_bLoaded = true;
|
||||
|
||||
if (bKID) {
|
||||
log::info("Keyword Item Distributor is detected.");
|
||||
} else {
|
||||
log::info("Keyword Item Distributor has NOT been detected, using the baseline configuration.");
|
||||
}
|
||||
|
||||
RE::ConsoleLog::GetSingleton()->Print(std::format("Artifact Tracker registered {} items.", g_artifactMap.size()).c_str());
|
||||
|
||||
log::info("Total artifacts: {}", g_artifactMap.size());
|
||||
|
||||
if (settings.at("DumpItemList")) {
|
||||
@ -143,6 +192,14 @@ namespace ArtifactTracker
|
||||
}
|
||||
}
|
||||
|
||||
if (dataHandler->LookupLoadedModByName("DBM_RelicNotifications.esp")) {
|
||||
RE::DebugMessageBox("Artifact Tracker is incompatible with The Curator's Companion.");
|
||||
}
|
||||
|
||||
if (!bKID && settings.at("WarnMissingKID")) {
|
||||
RE::DebugMessageBox("Artifact Tracker requires Keyword Item Distributor. If its absence is intentional, set WarnMissingKID=false in ArtifactTracker.ini.");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -172,7 +229,7 @@ namespace ArtifactTracker
|
||||
if (&a_exform) {
|
||||
g_persistentMap[a_exform.formID] = a_exform.As<RE::TESObjectREFR>();
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
|
||||
std::uint32_t savedCount = g_listStored->forms.size() + g_listFound->forms.size() + g_listNew->forms.size();
|
||||
@ -187,6 +244,7 @@ namespace ArtifactTracker
|
||||
const auto vm = RE::BSScript::Internal::VirtualMachine::GetSingleton();
|
||||
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
|
||||
|
||||
bool bMoreHUDInstalled = false;
|
||||
if (const auto pluginInfo = g_loadInterface->GetPluginInfo("Ahzaab's moreHUD Plugin"); pluginInfo) {
|
||||
if (!g_bLoaded) log::info("Detected {} v{}", pluginInfo->name, pluginInfo->version);
|
||||
if (pluginInfo->version == 0) {
|
||||
@ -198,6 +256,7 @@ namespace ArtifactTracker
|
||||
vm->DispatchStaticCall("AhzMoreHud", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmNew", std::move(g_listNew)), stackCallback);
|
||||
vm->DispatchStaticCall("AhzMoreHud", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmFound", std::move(g_listFound)), stackCallback);
|
||||
vm->DispatchStaticCall("AhzMoreHud", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmDisp", std::move(g_listStored)), stackCallback);
|
||||
bMoreHUDInstalled = true;
|
||||
} else {
|
||||
log::error("MoreHUD has not been installed correctly.");
|
||||
}
|
||||
@ -205,6 +264,7 @@ namespace ArtifactTracker
|
||||
log::error("MoreHUD has not been detected.");
|
||||
}
|
||||
|
||||
bool bMoreHUDInvInstalled = false;
|
||||
if (const auto pluginInfo = g_loadInterface->GetPluginInfo("Ahzaab's moreHUD Inventory Plugin"); pluginInfo) {
|
||||
if (!g_bLoaded) log::info("Detected {} v{}", pluginInfo->name, pluginInfo->version);
|
||||
if (pluginInfo->version == 0) {
|
||||
@ -216,6 +276,7 @@ namespace ArtifactTracker
|
||||
vm->DispatchStaticCall("AhzMoreHudIE", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmNew", std::move(g_listNew)), stackCallback);
|
||||
vm->DispatchStaticCall("AhzMoreHudIE", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmFound", std::move(g_listFound)), stackCallback);
|
||||
vm->DispatchStaticCall("AhzMoreHudIE", "RegisterIconFormList", RE::MakeFunctionArguments<RE::BSString, RE::BGSListForm*>("dbmDisp", std::move(g_listStored)), stackCallback);
|
||||
bool bMoreHUDInvInstalled = true;
|
||||
} else {
|
||||
log::error("MoreHUD Inventory Edition has not been installed correctly.");
|
||||
}
|
||||
@ -223,6 +284,10 @@ namespace ArtifactTracker
|
||||
log::error("MoreHUD Inventory Edition has not been detected.");
|
||||
}
|
||||
|
||||
if (g_bWarnMissingMoreHUD && !bMoreHUDInstalled && !bMoreHUDInvInstalled) {
|
||||
RE::DebugMessageBox("Artifact Tracker requires up-to-date MoreHUD and/or MoreHUD Inventory Edition. If their absence is intentional, set WarnMissingMoreHUD=false in ArtifactTracker.ini.");
|
||||
}
|
||||
|
||||
// TODO: Uncomment when/if QuickLoot EE brings back registering formlists
|
||||
/*
|
||||
if (const auto pluginInfo = g_loadInterface->GetPluginInfo("QuickLootEE"); pluginInfo) {
|
||||
@ -269,9 +334,7 @@ namespace ArtifactTracker
|
||||
g_bBookShelf = false;
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1200));
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
});
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
}).detach();
|
||||
} else {
|
||||
SyncCellStorage();
|
||||
@ -307,7 +370,7 @@ namespace ArtifactTracker
|
||||
|
||||
bool IsValidContainer(RE::TESObjectREFR* a_ref)
|
||||
{
|
||||
if (!a_ref) {
|
||||
if (!a_ref || a_ref->IsMarkedForDeletion()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -318,6 +381,11 @@ namespace ArtifactTracker
|
||||
|
||||
void OnCellEnter(const RE::FormID a_formID)
|
||||
{
|
||||
if (!g_bSaveLoaded) {
|
||||
// Cell load events fire before formlists are loaded from savegame
|
||||
return;
|
||||
}
|
||||
|
||||
RE::TESObjectCELL* cell = RE::TESForm::LookupByID<RE::TESObjectCELL>(a_formID);
|
||||
RE::BGSLocation* location = cell ? cell->GetLocation() : nullptr;
|
||||
|
||||
@ -330,40 +398,75 @@ namespace ArtifactTracker
|
||||
}
|
||||
|
||||
RE::TESObjectREFR* cellStorage = nullptr;
|
||||
bool bHasDupes = false;
|
||||
|
||||
g_persistentStorage->ForEachForm([&](RE::TESForm& a_form) {
|
||||
const auto refr = a_form.As<RE::TESObjectREFR>();
|
||||
if (refr && refr->GetParentCell()->formID == a_formID) {
|
||||
cellStorage = refr;
|
||||
return false;
|
||||
if (refr && refr->GetParentCell()->formID == a_formID && refr->GetBaseObject() == g_cellContainer) {
|
||||
if (cellStorage) {
|
||||
log::warn("Multiple cell storages detected in {}", cell->GetName());
|
||||
bHasDupes = true;
|
||||
} else {
|
||||
cellStorage = refr;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
|
||||
#ifdef _DEBUG
|
||||
if (cellStorage) {
|
||||
log::info("Found cell storage in {} (first pass)", cell->GetName());
|
||||
}
|
||||
#endif
|
||||
|
||||
ToggleHomeMode(cellStorage);
|
||||
|
||||
if (!cellStorage) {
|
||||
if (!cellStorage || bHasDupes) {
|
||||
RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink<RE::TESCellFullyLoadedEvent>(EventListener::GetSingleton());
|
||||
}
|
||||
}
|
||||
|
||||
void OnCellEnter(const RE::BGSLocation* location, const RE::TESObjectCELL* cell)
|
||||
{
|
||||
RE::ScriptEventSourceHolder::GetSingleton()->RemoveEventSink<RE::TESCellFullyLoadedEvent>(EventListener::GetSingleton());
|
||||
|
||||
if (!g_bSaveLoaded) {
|
||||
// Cell load events fire before formlists are loaded from savegame, duh!
|
||||
return;
|
||||
}
|
||||
|
||||
if (!location || !cell->IsInteriorCell() || cell != RE::PlayerCharacter::GetSingleton()->GetParentCell() || !location->HasKeyword(g_homeKeyword)) {
|
||||
ToggleHomeMode(nullptr);
|
||||
return;
|
||||
}
|
||||
|
||||
RE::TESObjectREFR* cellStorage = nullptr;
|
||||
std::vector<RE::TESObjectREFR*> dupes;
|
||||
|
||||
for (const auto& a_ref : cell->references) {
|
||||
if (a_ref.get()->GetBaseObject() == g_cellContainer) {
|
||||
cellStorage = a_ref.get();
|
||||
break;
|
||||
cell->ForEachReference([&cellStorage, &dupes](RE::TESObjectREFR& a_ref) {
|
||||
if (a_ref.GetBaseObject() == g_cellContainer && !a_ref.IsMarkedForDeletion()) {
|
||||
if (cellStorage) {
|
||||
dupes.push_back(&a_ref);
|
||||
} else {
|
||||
cellStorage = &a_ref;
|
||||
}
|
||||
}
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
|
||||
for (int i = 0; i < dupes.size(); i++) {
|
||||
log::warn("Removing duplicate storage {:08X}", dupes[i]->formID);
|
||||
g_persistentMap.erase(dupes[i]->formID);
|
||||
ListRemoveItem(g_persistentStorage, dupes[i]);
|
||||
dupes[i]->Disable();
|
||||
dupes[i]->SetDelete(true);
|
||||
}
|
||||
dupes.clear();
|
||||
|
||||
if (cellStorage) {
|
||||
#ifdef _DEBUG
|
||||
log::info("Found cell storage in {} (second pass)", cell->GetName());
|
||||
#endif
|
||||
if (!g_persistentMap.contains(cellStorage->formID)) {
|
||||
g_persistentStorage->AddForm(cellStorage);
|
||||
g_persistentMap[cellStorage->formID] = cellStorage;
|
||||
@ -377,10 +480,13 @@ namespace ArtifactTracker
|
||||
log::info("Adding new storage in {}", cell->GetName());
|
||||
#endif
|
||||
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
||||
SKSE::GetTaskInterface()->AddTask([]() {
|
||||
const auto cellStorage = RE::PlayerCharacter::GetSingleton()->PlaceObjectAtMe(g_cellContainer, true).get();
|
||||
|
||||
if (cellStorage) {
|
||||
#ifdef _DEBUG
|
||||
log::info("Created storage {:08X}", cellStorage->formID);
|
||||
#endif
|
||||
cellStorage->Disable();
|
||||
g_persistentStorage->AddForm(cellStorage);
|
||||
g_persistentMap[cellStorage->formID] = cellStorage;
|
||||
@ -406,83 +512,86 @@ namespace ArtifactTracker
|
||||
log::info("Running SyncCellStorage");
|
||||
#endif
|
||||
|
||||
std::unordered_set<RE::FormID> cellItems;
|
||||
const RE::FormID ignoreFormID = a_ignoreRef ? a_ignoreRef->formID : NULL;
|
||||
|
||||
const auto cell = g_cellStorage->GetParentCell();
|
||||
const auto inv = g_cellStorage->GetInventory();
|
||||
SKSE::GetTaskInterface()->AddTask([ignoreFormID]() {
|
||||
std::unordered_set<RE::FormID> cellItems;
|
||||
|
||||
cell->ForEachReference([&](RE::TESObjectREFR& a_ref) {
|
||||
if (a_ignoreRef && a_ignoreRef->formID == a_ref.formID) {
|
||||
return true;
|
||||
}
|
||||
const auto cell = g_cellStorage->GetParentCell();
|
||||
const auto inv = g_cellStorage->GetInventory();
|
||||
|
||||
const auto baseObj = a_ref.GetBaseObject();
|
||||
|
||||
if (IsValidContainer(&a_ref)) {
|
||||
if (g_cellContainer == baseObj || baseObj->formID == 0xDC9E7 || g_persistentMap.contains(a_ref.formID)) { // skip persistent and PlayerBookShelfContainer
|
||||
return true;
|
||||
cell->ForEachReference([&](RE::TESObjectREFR& a_ref) {
|
||||
if (ignoreFormID && ignoreFormID == a_ref.formID) {
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
}
|
||||
|
||||
const auto contInv = a_ref.GetInventory([&](RE::TESBoundObject& a_object) -> bool {
|
||||
return !cellItems.contains(a_object.formID) && IsArtifact(&a_object);
|
||||
});
|
||||
const auto baseObj = a_ref.GetBaseObject();
|
||||
|
||||
for (const auto& [item, data] : contInv) {
|
||||
if (data.first > 0) {
|
||||
cellItems.insert(item->formID);
|
||||
if (inv.find(item) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(item, nullptr, 1, nullptr);
|
||||
if (IsValidContainer(&a_ref)) {
|
||||
if (g_cellContainer == baseObj || baseObj->formID == 0xDC9E7 || g_persistentMap.contains(a_ref.formID)) { // skip persistent and PlayerBookShelfContainer
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
}
|
||||
|
||||
const auto contInv = a_ref.GetInventory([&](RE::TESBoundObject& a_object) -> bool {
|
||||
return !cellItems.contains(a_object.formID) && g_artifactAllFormTypes.contains(a_object.GetFormType());
|
||||
});
|
||||
|
||||
for (const auto& [item, data] : contInv) {
|
||||
if (data.first > 0) {
|
||||
cellItems.insert(item->formID);
|
||||
if (inv.find(item) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(item, nullptr, 1, nullptr);
|
||||
}
|
||||
if (IsArtifact(item) && !g_listStored->HasForm(item)) {
|
||||
ListRemoveItem(g_listNew, item);
|
||||
ListRemoveItem(g_listFound, item);
|
||||
g_listStored->AddForm(item);
|
||||
}
|
||||
}
|
||||
if (!g_listStored->HasForm(item)) {
|
||||
}
|
||||
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
}
|
||||
|
||||
if (!g_artifactAllFormTypes.contains(baseObj->GetFormType()) || a_ref.IsDisabled() || a_ref.IsMarkedForDeletion() || cellItems.contains(baseObj->formID)) {
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
}
|
||||
|
||||
cellItems.insert(baseObj->formID);
|
||||
|
||||
if (inv.find(baseObj) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(baseObj, nullptr, 1, nullptr);
|
||||
}
|
||||
|
||||
if (IsArtifact(baseObj) && !g_listStored->HasForm(baseObj)) {
|
||||
ListRemoveItem(g_listNew, baseObj);
|
||||
ListRemoveItem(g_listFound, baseObj);
|
||||
g_listStored->AddForm(baseObj);
|
||||
}
|
||||
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
|
||||
for (const auto& [item, data] : inv) {
|
||||
const auto& [count, entry] = data;
|
||||
if (count > 0 && !cellItems.contains(item->formID)) {
|
||||
g_cellStorage->RemoveItem(item, count, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr);
|
||||
|
||||
if (IsArtifact(item) && !RefListHasItem(g_persistentStorage, item->formID)) {
|
||||
ListRemoveItem(g_listStored, item);
|
||||
if (GetItemCount(RE::PlayerCharacter::GetSingleton(), item) || FollowersHaveItem(item)) {
|
||||
ListRemoveItem(g_listNew, item);
|
||||
g_listFound->AddForm(item);
|
||||
} else {
|
||||
ListRemoveItem(g_listFound, item);
|
||||
g_listStored->AddForm(item);
|
||||
g_listNew->AddForm(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
if (a_ref.IsDisabled() || a_ref.IsMarkedForDeletion() || cellItems.contains(baseObj->formID) || !IsArtifact(baseObj)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
cellItems.insert(baseObj->formID);
|
||||
|
||||
if (inv.find(baseObj) == inv.end()) {
|
||||
g_cellStorage->AddObjectToContainer(baseObj, nullptr, 1, nullptr);
|
||||
}
|
||||
|
||||
if (!g_listStored->HasForm(baseObj)) {
|
||||
ListRemoveItem(g_listNew, baseObj);
|
||||
ListRemoveItem(g_listFound, baseObj);
|
||||
g_listStored->AddForm(baseObj);
|
||||
}
|
||||
|
||||
return true;
|
||||
cellItems.clear();
|
||||
});
|
||||
|
||||
for (const auto& [item, data] : inv) {
|
||||
const auto& [count, entry] = data;
|
||||
if (count > 0 && !cellItems.contains(item->formID)) {
|
||||
|
||||
g_cellStorage->RemoveItem(item, count, RE::ITEM_REMOVE_REASON::kRemove, nullptr, nullptr);
|
||||
|
||||
if (!RefListHasItem(g_persistentStorage, item->formID)) {
|
||||
ListRemoveItem(g_listStored, item);
|
||||
if (GetItemCount(RE::PlayerCharacter::GetSingleton(), item) || FollowersHaveItem(item)) {
|
||||
ListRemoveItem(g_listNew, item);
|
||||
g_listFound->AddForm(item);
|
||||
} else {
|
||||
ListRemoveItem(g_listFound, item);
|
||||
g_listNew->AddForm(item);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellItems.clear();
|
||||
}
|
||||
|
||||
void OnContainerChanged(const RE::TESContainerChangedEvent* a_event, RE::TESForm* form)
|
||||
@ -571,10 +680,14 @@ namespace ArtifactTracker
|
||||
g_listStored->AddForm(form);
|
||||
}
|
||||
|
||||
} else if (a_event->oldContainer == 0x14 && !g_listStored->HasForm(form) && !GetItemCount(RE::PlayerCharacter::GetSingleton(), form) && !FollowersHaveItem(form)) {
|
||||
// disposed by player
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
} else if (a_event->oldContainer == 0x14 && !g_listStored->HasForm(form)) {
|
||||
SKSE::GetTaskInterface()->AddTask([form]() {
|
||||
if (!GetItemCount(RE::PlayerCharacter::GetSingleton(), form) && !FollowersHaveItem(form)) {
|
||||
// disposed by player
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -608,14 +721,18 @@ namespace ArtifactTracker
|
||||
} else if (a_event->oldContainer == 0x14) { // dropped, consumed, dismantled, removed by script
|
||||
|
||||
if (!g_listStored->HasForm(form)) {
|
||||
if (!GetItemCount(RE::PlayerCharacter::GetSingleton(), form) && !FollowersHaveItem(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
// Seems like OnContainerChanged runs concurrently with updating ContainerChanges.
|
||||
// In small modlists ContainerChanges may not be propagated yet in this event, so we need to schedule GetItemCount.
|
||||
SKSE::GetTaskInterface()->AddTask([form]() {
|
||||
if (!GetItemCount(RE::PlayerCharacter::GetSingleton(), form) && !FollowersHaveItem(form)) {
|
||||
ListRemoveItem(g_listFound, form);
|
||||
g_listNew->AddForm(form);
|
||||
|
||||
} else if (!g_listFound->HasForm(form)) {
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
} else if (!g_listFound->HasForm(form)) {
|
||||
ListRemoveItem(g_listNew, form);
|
||||
g_listFound->AddForm(form);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} else if (g_cellStorage && g_cellStorage->formID == a_event->oldContainer) {
|
||||
@ -698,7 +815,7 @@ namespace ArtifactTracker
|
||||
if (refrItem) {
|
||||
AddRefArtifactsToList(refrItem, a_targetList, a_excludeList);
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
return;
|
||||
}
|
||||
@ -759,7 +876,7 @@ namespace ArtifactTracker
|
||||
g_iFollowerIndex = iCurrentFollowers;
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(3000)); // wait for followers to load into the new cell
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
SKSE::GetTaskInterface()->AddTask([]() {
|
||||
RescanFoundArtifacts();
|
||||
});
|
||||
}).detach();
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
namespace ArtifactTracker
|
||||
{
|
||||
extern bool g_bLoaded;
|
||||
extern bool g_bSaveLoaded;
|
||||
extern bool g_bHomeContainer;
|
||||
extern bool g_bBookShelf;
|
||||
extern bool g_bTakeAll;
|
||||
@ -16,6 +17,7 @@ namespace ArtifactTracker
|
||||
extern RE::BGSKeyword* g_homeKeyword;
|
||||
extern std::unordered_map<RE::FormID, RE::TESForm*> g_artifactMap;
|
||||
extern std::unordered_set<RE::FormType> g_artifactFormTypes;
|
||||
extern std::unordered_set<RE::FormType> g_artifactAllFormTypes;
|
||||
extern std::unordered_map<RE::FormID, RE::TESObjectREFR*> g_persistentMap;
|
||||
extern RE::TESObjectREFR* g_cellStorage;
|
||||
extern const SKSE::LoadInterface* g_loadInterface;
|
||||
|
||||
@ -10,7 +10,7 @@ auto EventListener::GetSingleton() -> EventListener*
|
||||
|
||||
void EventListener::Install()
|
||||
{
|
||||
RE::PlayerCharacter::GetSingleton()->AddEventSink<RE::BGSActorCellEvent>(EventListener::GetSingleton());
|
||||
RE::PlayerCharacter::GetSingleton()->AsBGSActorCellEventSource()->AddEventSink<RE::BGSActorCellEvent>(EventListener::GetSingleton());
|
||||
RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink<RE::TESContainerChangedEvent>(EventListener::GetSingleton());
|
||||
RE::ScriptEventSourceHolder::GetSingleton()->AddEventSink<RE::TESActorLocationChangeEvent>(EventListener::GetSingleton());
|
||||
RE::UI::GetSingleton()->AddEventSink<RE::MenuOpenCloseEvent>(EventListener::GetSingleton());
|
||||
@ -65,11 +65,12 @@ auto EventListener::ProcessEvent(
|
||||
RE::BSTEventSource<RE::TESCellFullyLoadedEvent>* a_eventSource)
|
||||
-> RE::BSEventNotifyControl
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("TESCellFullyLoadedEvent");
|
||||
#endif
|
||||
|
||||
ArtifactTracker::OnCellEnter(a_event->cell->GetLocation(), a_event->cell);
|
||||
if (a_event->cell) {
|
||||
#ifdef _DEBUG
|
||||
SKSE::log::info("TESCellFullyLoadedEvent");
|
||||
#endif
|
||||
ArtifactTracker::OnCellEnter(a_event->cell->GetLocation(), a_event->cell);
|
||||
}
|
||||
|
||||
return RE::BSEventNotifyControl::kContinue;
|
||||
}
|
||||
@ -84,22 +85,26 @@ auto EventListener::ProcessEvent(
|
||||
SKSE::log::info("MenuOpenCloseEvent");
|
||||
#endif
|
||||
|
||||
if (a_event->opening) {
|
||||
RE::BSInputDeviceManager::GetSingleton()->AddEventSink(EventListener::GetSingleton());
|
||||
} else {
|
||||
RE::BSInputDeviceManager::GetSingleton()->RemoveEventSink(EventListener::GetSingleton());
|
||||
if (ArtifactTracker::g_bTakeAll && ArtifactTracker::g_bNotifyNewArtifact && ArtifactTracker::g_bTakeAllCount > 0) {
|
||||
//RE::DebugNotification(fmt::format("{} new artifact(s) acquired", ArtifactTracker::g_bTakeAllCount).c_str());
|
||||
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
|
||||
RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("ETR_NewArtifactsCombinedNotification", "Show", RE::MakeFunctionArguments<std::uint32_t>(std::move(ArtifactTracker::g_bTakeAllCount)), stackCallback);
|
||||
}
|
||||
ArtifactTracker::g_bTakeAll = false;
|
||||
ArtifactTracker::g_bTakeAllCount = 0;
|
||||
}
|
||||
bool bOpening = a_event->opening;
|
||||
|
||||
if (ArtifactTracker::IsHome()) {
|
||||
ArtifactTracker::SetContainerMode(a_event->opening);
|
||||
}
|
||||
SKSE::GetTaskInterface()->AddTask([bOpening]() {
|
||||
if (bOpening) {
|
||||
RE::BSInputDeviceManager::GetSingleton()->AddEventSink(EventListener::GetSingleton());
|
||||
} else {
|
||||
RE::BSInputDeviceManager::GetSingleton()->RemoveEventSink(EventListener::GetSingleton());
|
||||
if (ArtifactTracker::g_bTakeAll && ArtifactTracker::g_bNotifyNewArtifact && ArtifactTracker::g_bTakeAllCount > 0) {
|
||||
//RE::DebugNotification(fmt::format("{} new artifact(s) acquired", ArtifactTracker::g_bTakeAllCount).c_str());
|
||||
RE::BSTSmartPointer<RE::BSScript::IStackCallbackFunctor> stackCallback;
|
||||
RE::BSScript::Internal::VirtualMachine::GetSingleton()->DispatchStaticCall("ETR_NewArtifactsCombinedNotification", "Show", RE::MakeFunctionArguments<std::uint32_t>(std::move(ArtifactTracker::g_bTakeAllCount)), stackCallback);
|
||||
}
|
||||
ArtifactTracker::g_bTakeAll = false;
|
||||
ArtifactTracker::g_bTakeAllCount = 0;
|
||||
}
|
||||
|
||||
if (ArtifactTracker::IsHome()) {
|
||||
ArtifactTracker::SetContainerMode(bOpening);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return RE::BSEventNotifyControl::kContinue;
|
||||
@ -113,12 +118,10 @@ auto EventListener::ProcessEvent(
|
||||
// This listener is expected to be unregistered outside of home.
|
||||
if (ArtifactTracker::IsHome() && a_event->actionRef->IsPlayerRef() && a_event->objectActivated) {
|
||||
const auto ref = a_event->objectActivated.get();
|
||||
if (ref && ArtifactTracker::IsArtifact(ref->GetBaseObject())) {
|
||||
if (ref && ArtifactTracker::g_artifactAllFormTypes.contains(ref->GetBaseObject()->GetFormType())) {
|
||||
std::thread([]() {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(200));
|
||||
SKSE::GetTaskInterface()->AddTask([&]() {
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
});
|
||||
ArtifactTracker::SyncCellStorage();
|
||||
}).detach();
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,8 @@ namespace {
|
||||
stl::report_and_fail("Failed to find standard logging directory"sv);
|
||||
}
|
||||
|
||||
*path /= "ArtifactTracker.log"sv;
|
||||
*path /= PluginDeclaration::GetSingleton()->GetName();
|
||||
*path += ".log"sv;
|
||||
auto sink = std::make_shared<spdlog::sinks::basic_file_sink_mt>(path->string(), true);
|
||||
|
||||
auto log = std::make_shared<spdlog::logger>("global log"s, std::move(sink));
|
||||
@ -28,14 +29,23 @@ namespace {
|
||||
void InitializeMessaging()
|
||||
{
|
||||
GetMessagingInterface()->RegisterListener([](MessagingInterface::Message* message) {
|
||||
if (message->type == MessagingInterface::kPostLoad) {
|
||||
SKSE::GetModCallbackEventSource()->AddEventSink(EventListener::GetSingleton()); // runs, if KID is installed
|
||||
} else if (message->type == MessagingInterface::kDataLoaded) {
|
||||
if (const auto pluginInfo = ArtifactTracker::g_loadInterface->GetPluginInfo("po3_KeywordItemDistributor"); !pluginInfo) {
|
||||
if (message->type == MessagingInterface::kDataLoaded) {
|
||||
const auto kidSE = ArtifactTracker::g_loadInterface->GetPluginInfo("po3_KeywordItemDistributor");
|
||||
const auto kidAE = ArtifactTracker::g_loadInterface->GetPluginInfo("Keyword Item Distributor"); // KID 2.0 for AE has a different internal name
|
||||
if (!kidSE && !kidAE) {
|
||||
ArtifactTracker::Init(); // if KID is not installed
|
||||
}
|
||||
} else if (message->type == MessagingInterface::kPostLoadGame) {
|
||||
ArtifactTracker::OnGameLoad(); // save-specific updates
|
||||
} else if (message->type == MessagingInterface::kPreLoadGame) {
|
||||
ArtifactTracker::g_bSaveLoaded = false; // block cell load events
|
||||
} else if (message->type == MessagingInterface::kPostLoadGame && message->data) {
|
||||
const auto cell = RE::PlayerCharacter::GetSingleton()->GetParentCell();
|
||||
if (cell) {
|
||||
SKSE::GetTaskInterface()->AddTask([cell]() {
|
||||
ArtifactTracker::OnGameLoad(); // save-specific updates
|
||||
ArtifactTracker::g_bSaveLoaded = true;
|
||||
ArtifactTracker::OnCellEnter(cell->GetLocation(), cell);
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@ -53,6 +63,8 @@ SKSEPluginLoad(const LoadInterface* skse) {
|
||||
|
||||
ArtifactTracker::g_loadInterface = skse;
|
||||
|
||||
SKSE::GetModCallbackEventSource()->AddEventSink(EventListener::GetSingleton()); // runs when KID is installed
|
||||
|
||||
log::info("{} has finished loading.", plugin->GetName());
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -42,9 +42,9 @@ inline std::uint32_t GetItemCount(RE::TESObjectREFR* a_container, RE::TESForm* a
|
||||
container->ForEachContainerObject([&](RE::ContainerObject& a_entry) {
|
||||
if (a_entry.obj == a_form) {
|
||||
iResult += a_entry.count;
|
||||
return false;
|
||||
return RE::BSContainer::ForEachResult::kStop;
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
}
|
||||
|
||||
@ -74,9 +74,9 @@ inline std::int32_t GetItemCount(RE::TESObjectREFR* a_container, RE::FormID a_fo
|
||||
container->ForEachContainerObject([&](RE::ContainerObject& a_entry) {
|
||||
if (a_entry.obj && a_entry.obj->formID == a_formID) {
|
||||
iResult += a_entry.count;
|
||||
return false;
|
||||
return RE::BSContainer::ForEachResult::kStop;
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
}
|
||||
|
||||
@ -103,9 +103,9 @@ inline bool RefListHasItem(RE::TESForm* a_refOrList, RE::FormID a_formID)
|
||||
list->ForEachForm([&](RE::TESForm& a_form) {
|
||||
if (&a_form && RefListHasItem(&a_form, a_formID)) {
|
||||
bResult = true;
|
||||
return false;
|
||||
return RE::BSContainer::ForEachResult::kStop;
|
||||
}
|
||||
return true;
|
||||
return RE::BSContainer::ForEachResult::kContinue;
|
||||
});
|
||||
return bResult;
|
||||
}
|
||||
@ -178,10 +178,11 @@ inline void LoadINI(std::map<std::string, bool>* settings, const char* iniPath)
|
||||
}
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
log::error(e.what());
|
||||
log::error("{}", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
inline void RunBenchmark(std::function<void()> benchmark, std::string desc)
|
||||
{
|
||||
const auto start = std::chrono::high_resolution_clock::now();
|
||||
@ -191,6 +192,7 @@ inline void RunBenchmark(std::function<void()> benchmark, std::string desc)
|
||||
const auto elapsed = std::chrono::duration<double>(end - start);
|
||||
log::info("{}: Elapsed time: {} seconds", desc, elapsed.count());
|
||||
}
|
||||
*/
|
||||
|
||||
inline std::vector<RE::Actor*> GetPlayerFollowers()
|
||||
{
|
||||
|
||||
@ -1,15 +1,15 @@
|
||||
{
|
||||
"registries": [
|
||||
{
|
||||
"kind": "git",
|
||||
"repository": "https://gitlab.com/colorglass/vcpkg-colorglass",
|
||||
"baseline": "5a11d06fd1b2d7cd6339d6aea48d450309e89cc1",
|
||||
"packages": [
|
||||
"commonlibsse-ng",
|
||||
"gluino",
|
||||
"script-extender-common",
|
||||
"skse"
|
||||
]
|
||||
}
|
||||
{
|
||||
"kind": "git",
|
||||
"repository": "https://gitlab.com/colorglass/vcpkg-colorglass",
|
||||
"baseline": "6309841a1ce770409708a67a9ba5c26c537d2937",
|
||||
"packages": [
|
||||
"commonlibsse-ng",
|
||||
"gluino",
|
||||
"script-extender-common",
|
||||
"skse"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@ -1,11 +1,11 @@
|
||||
{
|
||||
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
|
||||
"name": "artifact-tracker",
|
||||
"version-string": "1.0.1",
|
||||
"version-string": "1.0.11",
|
||||
"port-version": 0,
|
||||
"description": "Artifact Tracker",
|
||||
"homepage": "https://eddoursul.win/mods/artifact-tracker/",
|
||||
"license": "LGPL-3.0",
|
||||
"homepage": "https://mod.pub/skyrim-se/36-artifact-tracker",
|
||||
"license": null,
|
||||
"features": {
|
||||
"plugin": {
|
||||
"description": "Tracks found and stored artifacts.",
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user