diff --git a/.gitignore b/.gitignore index 98d05f0..c175678 100644 --- a/.gitignore +++ b/.gitignore @@ -333,4 +333,8 @@ ASALocalRun/ # Local History for Visual Studio .localhistory/ -x64 \ No newline at end of file +x64 +dependencies/skse64/src/common/x64_v142 +executables +vcpkg_installed +x64_v142 diff --git a/SkyrimOutfitSystemSE.sln b/SkyrimOutfitSystemSE.sln index f4023ea..423ef80 100644 --- a/SkyrimOutfitSystemSE.sln +++ b/SkyrimOutfitSystemSE.sln @@ -1,7 +1,7 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 15 -VisualStudioVersion = 15.0.28307.1259 +# Visual Studio Version 16 +VisualStudioVersion = 16.0.30517.126 MinimumVisualStudioVersion = 10.0.40219.1 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "SkyrimOutfitSystemSE", "SkyrimOutfitSystemSE.vcxproj", "{10D1A242-54ED-467F-846C-E84EBD82FB7D}" EndProject @@ -27,18 +27,18 @@ Global {C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Debug|x64.Build.0 = Debug|x64 {C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Release|x64.ActiveCfg = Release|x64 {C1AF9204-EE2D-421B-B11E-1D70D8ACC11F}.Release|x64.Build.0 = Release|x64 - {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.ActiveCfg = Debug|x64 - {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.Build.0 = Debug|x64 - {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.ActiveCfg = Release|x64 - {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.Build.0 = Release|x64 - {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.ActiveCfg = Debug|x64 - {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.Build.0 = Debug|x64 - {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.ActiveCfg = Release|x64 - {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.Build.0 = Release|x64 - {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.ActiveCfg = Debug|x64 - {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.Build.0 = Debug|x64 - {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.ActiveCfg = Release|x64 - {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.Build.0 = Release|x64 + {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.ActiveCfg = Debug_Lib_VC142|x64 + {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Debug|x64.Build.0 = Debug_Lib_VC142|x64 + {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.ActiveCfg = Release_Lib_VC142|x64 + {7028B79C-06E3-4D9A-B38C-1DC3680B1BDB}.Release|x64.Build.0 = Release_Lib_VC142|x64 + {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.ActiveCfg = Debug_VC142|x64 + {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Debug|x64.Build.0 = Debug_VC142|x64 + {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.ActiveCfg = Release_VC142|x64 + {5FD1C08D-DB80-480C-A1C6-F0920005CD13}.Release|x64.Build.0 = Release_VC142|x64 + {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.ActiveCfg = Debug_VC142|x64 + {472E19AB-DEF0-42DF-819B-18722E8DC822}.Debug|x64.Build.0 = Debug_VC142|x64 + {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.ActiveCfg = Release_VC142|x64 + {472E19AB-DEF0-42DF-819B-18722E8DC822}.Release|x64.Build.0 = Release_VC142|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/SkyrimOutfitSystemSE.vcxproj b/SkyrimOutfitSystemSE.vcxproj index 5ab3908..35c5a47 100644 --- a/SkyrimOutfitSystemSE.vcxproj +++ b/SkyrimOutfitSystemSE.vcxproj @@ -53,6 +53,14 @@ false dependencies\CommonLibSSE\include;include;dependencies\skse64\src;dependencies\skse64\src\skse64;$(IncludePath) + + true + true + + + true + true + Disabled @@ -175,11 +183,13 @@ {c1af9204-ee2d-421b-b11e-1d70d8acc11f} + + {7028b79c-06e3-4d9a-b38c-1dc3680b1bdb} + {5fd1c08d-db80-480c-a1c6-f0920005cd13} - - + \ No newline at end of file diff --git a/include/ArmorAddonOverrideService.h b/include/ArmorAddonOverrideService.h index d1a2681..c7f12b1 100644 --- a/include/ArmorAddonOverrideService.h +++ b/include/ArmorAddonOverrideService.h @@ -26,7 +26,7 @@ struct Outfit { void load(SKSESerializationInterface* intfc, UInt32 version); // can throw ArmorAddonOverrideService::load_error void save(SKSESerializationInterface*) const; // can throw ArmorAddonOverrideService::save_error }; -const char* g_noOutfitName = ""; +const constexpr char* g_noOutfitName = ""; static Outfit g_noOutfit(g_noOutfitName); // can't be const; prevents us from assigning it to Outfit&s class ArmorAddonOverrideService { diff --git a/src/ArmorAddonOverrideService.cpp b/src/ArmorAddonOverrideService.cpp index ab23a9c..5a8d317 100644 --- a/src/ArmorAddonOverrideService.cpp +++ b/src/ArmorAddonOverrideService.cpp @@ -47,7 +47,7 @@ void Outfit::load(SKSESerializationInterface* intfc, UInt32 version) { _assertRead(ReadData(intfc, &formID), "Failed to read an outfit's armor."); UInt32 fixedID; if (intfc->ResolveFormId(formID, &fixedID)) { - auto armor = reinterpret_cast(DYNAMIC_CAST(LookupFormByID(fixedID), TESForm, TESObjectARMO)); + auto armor = reinterpret_cast(Runtime_DynamicCast((void*) LookupFormByID(fixedID), RTTI_TESForm, RTTI_TESObjectARMO)); if (armor) this->armors.insert(armor); } diff --git a/src/OutfitSystem.cpp b/src/OutfitSystem.cpp index d63226c..7cbd333 100644 --- a/src/OutfitSystem.cpp +++ b/src/OutfitSystem.cpp @@ -5,12 +5,17 @@ #include "skse64/PapyrusVM.h" #include "skse64/GameRTTI.h" +#include "skse64/GameFormComponents.h" +#include "skse64/GameObjects.h" +#include "skse64/GameReferences.h" #include "RE/FormComponents/TESForm/TESObject/TESBoundObject/TESObjectARMO.h" #include "RE/FileIO/TESDataHandler.h" #include "RE/FormComponents/TESForm/TESObjectREFR/Actor/Actor.h" +#include "RE/AI/AIProcess.h" #include "RE/Inventory/InventoryChanges.h" #include "RE/Inventory/InventoryEntryData.h" + #include "ArmorAddonOverrideService.h" #include "cobb/strings.h" @@ -24,11 +29,13 @@ SInt32 GetOutfitNameMaxLength(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { return ArmorAddonOverrideService::ce_outfitNameMaxLength; } - VMResultArray GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) { + VMResultArray GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) { VMResultArray result; + auto target = (RE::Actor*) (target_skse); if (target == nullptr) { registry->LogError("Cannot retrieve data for a None actor.", stackId); - return result; + VMResultArray empty; + return empty; } // class _Visitor : public RE::InventoryChanges::IItemChangeVisitor { @@ -37,11 +44,12 @@ // shield, then we need to grab the equipped shield's worn-flags. // public: - virtual ReturnType Visit(RE::InventoryEntryData* data) override { - const auto form = data->type; + virtual bool Visit(RE::InventoryEntryData* data) override { + // Return true to continue, or else false to break. + const auto form = data->object; if (form && form->formType == RE::FormType::Armor) this->list.push_back(reinterpret_cast(form)); - return ReturnType::kContinue; + return true; }; VMResultArray& list; @@ -53,13 +61,20 @@ _Visitor visitor(result); inventory->ExecuteVisitor(&visitor); } - return result; + VMResultArray converted_result; + converted_result.reserve(result.size()); + for (const auto ptr : result) { + converted_result.push_back((TESObjectARMO*)ptr); + } + return converted_result; } - VMResultArray GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) { + VMResultArray GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) { VMResultArray result; + auto target = (RE::Actor*) (target_skse); if (target == nullptr) { registry->LogError("Cannot retrieve data for a None actor.", stackId); - return result; + VMResultArray empty; + return empty; } // class _Visitor : public RE::InventoryChanges::IItemChangeVisitor { @@ -68,11 +83,11 @@ // shield, then we need to grab the equipped shield's worn-flags. // public: - virtual ReturnType Visit(RE::InventoryEntryData* data) override { - auto form = data->type; + virtual bool Visit(RE::InventoryEntryData* data) override { + auto form = data->object; if (form && form->formType == RE::FormType::Armor) this->list.push_back(reinterpret_cast(form)); - return ReturnType::kContinue; + return true; }; VMResultArray& list; @@ -84,11 +99,17 @@ _Visitor visitor(result); inventory->ExecuteVisitorOnWorn(&visitor); } - return result; + VMResultArray converted_result; + converted_result.reserve(result.size()); + for (const auto ptr : result) { + converted_result.push_back((TESObjectARMO*)ptr); + } + return converted_result; } - void RefreshArmorFor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) { + void RefreshArmorFor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) { + auto target = (RE::Actor*) (target_skse); ERROR_AND_RETURN_IF(target == nullptr, "Cannot refresh armor on a None actor.", registry, stackId); - auto pm = target->processManager; + auto pm = target->currentProcess; if (pm) { // // "SetEquipFlag" tells the process manager that the actor's @@ -97,7 +118,8 @@ // should see a call near the start of EquipManager's func- // tion to equip an item. // - pm->SetEquipFlag(RE::ActorProcessManager::Flag::kUnk01); + // NOTE: AIProcess is also called as ActorProcessManager + pm->SetEquipFlag(RE::AIProcess::Flag::kUnk01); pm->UpdateEquipment(target); } } @@ -110,7 +132,7 @@ void setup(std::string nameFilter, bool mustBePlayable) { auto data = RE::TESDataHandler::GetSingleton(); auto& list = data->GetFormArray(RE::FormType::Armor); - const auto size = list.GetSize(); + const auto size = list.size(); this->names.reserve(size); this->armors.reserve(size); for (UInt32 i = 0; i < size; i++) { @@ -119,11 +141,12 @@ auto armor = static_cast(form); if (armor->templateArmor) // filter out predefined enchanted variants, to declutter the list continue; - if (mustBePlayable && !!(armor->flags & 4)) + if (mustBePlayable && !!(armor->formFlags & RE::TESObjectARMO::RecordFlags::kNonPlayable)) continue; std::string armorName; { // get name - TESFullName* tfn = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName); + // TESFullName* tfn = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName); + TESFullName* tfn = (TESFullName*)Runtime_DynamicCast((void*)armor, RTTI_TESObjectARMO, RTTI_TESFullName); if (tfn) armorName = tfn->name.data; } @@ -153,12 +176,17 @@ void Prep(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString filter, bool mustBePlayable) { data.setup(filter.data, mustBePlayable); } - VMResultArray GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { + VMResultArray GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { VMResultArray result; auto& list = data.armors; for (auto it = list.begin(); it != list.end(); it++) result.push_back(*it); - return result; + VMResultArray converted_result; + converted_result.reserve(result.size()); + for (const auto ptr : result) { + converted_result.push_back((TESObjectARMO*)ptr); + } + return converted_result; } VMResultArray GetNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { VMResultArray result; @@ -204,7 +232,8 @@ data.bodySlots.push_back(i); data.armors.push_back(armor); { // name - TESFullName* pFullName = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName); + // TESFullName* pFullName = DYNAMIC_CAST(armor, TESObjectARMO, TESFullName); + TESFullName* pFullName = (TESFullName*) Runtime_DynamicCast((void*) armor, RTTI_TESObjectARMO, RTTI_TESFullName); if (pFullName) data.armorNames.push_back(pFullName->name.data); else @@ -218,12 +247,17 @@ registry->LogWarning("The specified outfit does not exist.", stackId); } } - VMResultArray GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { + VMResultArray GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { VMResultArray result; auto& list = data.armors; for (auto it = list.begin(); it != list.end(); it++) result.push_back(*it); - return result; + VMResultArray converted_result; + converted_result.reserve(result.size()); + for (const auto ptr : result) { + converted_result.push_back((TESObjectARMO*)ptr); + } + return converted_result; } VMResultArray GetArmorNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { VMResultArray result; @@ -343,7 +377,8 @@ } } // - void AddArmorToOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, RE::TESObjectARMO* armor) { + void AddArmorToOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, TESObjectARMO* armor_skse) { + auto armor = (RE::TESObjectARMO*) (armor_skse); ERROR_AND_RETURN_IF(armor == nullptr, "Cannot add a None armor to an outfit.", registry, stackId); auto& service = ArmorAddonOverrideService::GetInstance(); try { @@ -354,7 +389,8 @@ registry->LogWarning("The specified outfit does not exist.", stackId); } } - bool ArmorConflictsWithOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::TESObjectARMO* armor, BSFixedString name) { + bool ArmorConflictsWithOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, TESObjectARMO* armor_skse, BSFixedString name) { + auto armor = (RE::TESObjectARMO*) (armor_skse); if (armor == nullptr) { registry->LogWarning("A None armor can't conflict with anything in an outfit.", stackId); return false; @@ -383,7 +419,7 @@ auto& service = ArmorAddonOverrideService::GetInstance(); service.deleteOutfit(name.data); } - VMResultArray GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) { + VMResultArray GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) { VMResultArray result; auto& service = ArmorAddonOverrideService::GetInstance(); try { @@ -395,7 +431,12 @@ catch (std::out_of_range) { registry->LogWarning("The specified outfit does not exist.", stackId); } - return result; + VMResultArray converted_result; + converted_result.reserve(result.size()); + for (const auto ptr : result) { + converted_result.push_back((TESObjectARMO*)ptr); + } + return converted_result; } BSFixedString GetSelectedOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) { auto& service = ArmorAddonOverrideService::GetInstance(); @@ -415,7 +456,8 @@ result.push_back(it->c_str()); return result; } - void RemoveArmorFromOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, RE::TESObjectARMO* armor) { + void RemoveArmorFromOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, TESObjectARMO* armor_skse) { + auto armor = (RE::TESObjectARMO*) (armor_skse); ERROR_AND_RETURN_IF(armor == nullptr, "Cannot remove a None armor from an outfit.", registry, stackId); auto& service = ArmorAddonOverrideService::GetInstance(); try { @@ -426,7 +468,8 @@ registry->LogWarning("The specified outfit does not exist.", stackId); } } - void RemoveConflictingArmorsFrom(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::TESObjectARMO* armor, BSFixedString name) { + void RemoveConflictingArmorsFrom(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, TESObjectARMO* armor_skse, BSFixedString name) { + auto armor = (RE::TESObjectARMO*) (armor_skse); ERROR_AND_RETURN_IF(armor == nullptr, "A None armor can't conflict with anything in an outfit.", registry, stackId); auto& service = ArmorAddonOverrideService::GetInstance(); try { @@ -438,7 +481,7 @@ RE::TESObjectARMO* existing = *it; if (existing) { const auto mask = existing->GetSlotMask(); - if ((mask & candidateMask) != RE::BGSBipedObjectForm::FirstPersonFlag::kNone) + if ((static_cast(mask) & static_cast(candidateMask)) != static_cast(RE::BGSBipedObjectForm::FirstPersonFlag::kNone)) conflicts.push_back(existing); } } @@ -473,15 +516,24 @@ auto& service = ArmorAddonOverrideService::GetInstance(); return service.hasOutfit(name.data); } - void OverwriteOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, VMArray armors) { + void OverwriteOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, VMArray armors_skse) { auto& service = ArmorAddonOverrideService::GetInstance(); + // Convert input array. + VMResultArray armors; + armors.reserve(armors_skse.Length()); + for (std::size_t i = 0; i < armors_skse.Length(); i++) { + TESObjectARMO* ptr; + armors_skse.Get(&ptr, i); + armors.push_back((RE::TESObjectARMO*)ptr); + } + // End convert try { auto& outfit = service.getOrCreateOutfit(name.data); outfit.armors.clear(); - auto count = armors.Length(); + auto count = armors.size(); for (UInt32 i = 0; i < count; i++) { RE::TESObjectARMO* ptr = nullptr; - armors.Get(&ptr, i); + ptr = armors.at(i); if (ptr) outfit.armors.insert(ptr); } @@ -510,19 +562,19 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { registry )); registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "GetOutfitNameMaxLength", VMClassRegistry::kFunctionFlag_NoWait); - registry->RegisterFunction(new NativeFunction1, RE::Actor*>( + registry->RegisterFunction(new NativeFunction1, Actor*>( "GetCarriedArmor", "SkyrimOutfitSystemNativeFuncs", GetCarriedArmor, registry )); - registry->RegisterFunction(new NativeFunction1, RE::Actor*>( + registry->RegisterFunction(new NativeFunction1, Actor*>( "GetWornItems", "SkyrimOutfitSystemNativeFuncs", GetWornItems, registry )); - registry->RegisterFunction(new NativeFunction1( + registry->RegisterFunction(new NativeFunction1( "RefreshArmorFor", "SkyrimOutfitSystemNativeFuncs", RefreshArmorFor, @@ -536,7 +588,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { ArmorFormSearchUtils::Prep, registry )); - registry->RegisterFunction(new NativeFunction0>( + registry->RegisterFunction(new NativeFunction0>( "GetArmorSearchResultForms", "SkyrimOutfitSystemNativeFuncs", ArmorFormSearchUtils::GetForms, @@ -562,7 +614,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { BodySlotListing::Prep, registry )); - registry->RegisterFunction(new NativeFunction0>( + registry->RegisterFunction(new NativeFunction0>( "GetOutfitBodySlotListingArmorForms", "SkyrimOutfitSystemNativeFuncs", BodySlotListing::GetArmorForms, @@ -595,10 +647,10 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { registry )); registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "NaturalSort_ASCII", VMClassRegistry::kFunctionFlag_NoWait); - registry->RegisterFunction(new NativeFunction3, VMArray, VMArray, bool>( + registry->RegisterFunction(new NativeFunction3, VMArray, VMArray, bool>( "NaturalSortPairArmor_ASCII", "SkyrimOutfitSystemNativeFuncs", - StringSorts::NaturalSortPair_ASCII, + StringSorts::NaturalSortPair_ASCII, registry )); registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "NaturalSortPairArmor_ASCII", VMClassRegistry::kFunctionFlag_NoWait); @@ -620,13 +672,13 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { registry->SetFunctionFlags("SkyrimOutfitSystemNativeFuncs", "ToHex", VMClassRegistry::kFunctionFlag_NoWait); } // - registry->RegisterFunction(new NativeFunction2( + registry->RegisterFunction(new NativeFunction2( "AddArmorToOutfit", "SkyrimOutfitSystemNativeFuncs", AddArmorToOutfit, registry )); - registry->RegisterFunction(new NativeFunction2( + registry->RegisterFunction(new NativeFunction2( "ArmorConflictsWithOutfit", "SkyrimOutfitSystemNativeFuncs", ArmorConflictsWithOutfit, @@ -644,7 +696,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { DeleteOutfit, registry )); - registry->RegisterFunction(new NativeFunction1, BSFixedString>( + registry->RegisterFunction(new NativeFunction1, BSFixedString>( "GetOutfitContents", "SkyrimOutfitSystemNativeFuncs", GetOutfitContents, @@ -668,13 +720,13 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { ListOutfits, registry )); - registry->RegisterFunction(new NativeFunction2( + registry->RegisterFunction(new NativeFunction2( "RemoveArmorFromOutfit", "SkyrimOutfitSystemNativeFuncs", RemoveArmorFromOutfit, registry )); - registry->RegisterFunction(new NativeFunction2( + registry->RegisterFunction(new NativeFunction2( "RemoveConflictingArmorsFrom", "SkyrimOutfitSystemNativeFuncs", RemoveConflictingArmorsFrom, @@ -692,7 +744,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) { OutfitExists, registry )); - registry->RegisterFunction(new NativeFunction2>( + registry->RegisterFunction(new NativeFunction2>( "OverwriteOutfit", "SkyrimOutfitSystemNativeFuncs", OverwriteOutfit, diff --git a/src/PlayerSkinning.cpp b/src/PlayerSkinning.cpp index 1b7a6b3..277774c 100644 --- a/src/PlayerSkinning.cpp +++ b/src/PlayerSkinning.cpp @@ -6,8 +6,10 @@ #include "RE/FormComponents/TESForm/TESObjectREFR/Actor/Character/PlayerCharacter.h" #include "RE/FormComponents/TESForm/TESObject/TESBoundObject/TESObjectARMO.h" #include "RE/FormComponents/TESForm/TESObjectREFR/TESObjectREFR.h" +#include "RE/FormComponents/TESForm/TESForm.h" #include "ArmorAddonOverrideService.h" +#include "skse64_common/Relocation.h" #include "skse64_common/BranchTrampoline.h" #include "skse64/GameRTTI.h" #include "RE/Inventory/ActorEquipManager.h" @@ -35,7 +37,7 @@ namespace OutfitSystem bool _stdcall ShouldOverride(RE::TESObjectARMO* armor, RE::TESObjectREFR* target) { if (!ShouldOverrideSkinning(target)) return false; - if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { + if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { auto& svc = ArmorAddonOverrideService::GetInstance(); auto& outfit = svc.currentOutfit(); if (!outfit.hasShield()) { @@ -108,16 +110,16 @@ namespace OutfitSystem // shield, then we need to grab the equipped shield's worn-flags. // public: - virtual ReturnType Visit(RE::InventoryEntryData* data) override { - auto form = data->type; + virtual bool Visit(RE::InventoryEntryData* data) override { + auto form = data->object; if (form && form->formType == RE::FormType::Armor) { auto armor = reinterpret_cast(form); - if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { + if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { this->mask |= static_cast(armor->GetSlotMask()); this->hasShield = true; } } - return ReturnType::kContinue; + return true; // Return true to "continue visiting". }; UInt32 mask = 0; @@ -140,7 +142,7 @@ namespace OutfitSystem for (auto armor : armors) { if (armor) { - if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { + if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { if (!shield) continue; } @@ -219,16 +221,16 @@ namespace OutfitSystem // shield, then we need to grab the equipped shield's worn-flags. // public: - virtual ReturnType Visit(RE::InventoryEntryData* data) override { - auto form = data->type; + virtual bool Visit(RE::InventoryEntryData* data) override { + auto form = data->object; if (form && form->formType == RE::FormType::Armor) { auto armor = reinterpret_cast(form); - if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { + if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { this->result = true; - return ReturnType::kBreak; // halt visitor early + return false; // False halt visitor early } } - return ReturnType::kContinue; + return true; // True to continue visiting }; bool result = false; }; @@ -236,7 +238,7 @@ namespace OutfitSystem void Custom(RE::Actor* target, RE::ActorWeightModel * actorWeightModel) { if (!actorWeightModel) return; - auto base = reinterpret_cast(DYNAMIC_CAST(target->baseForm, TESForm, TESNPC)); + auto base = reinterpret_cast(Runtime_DynamicCast(static_cast(target->data.objectReference), RTTI_TESForm, RTTI_TESNPC)); if (!base) return; auto race = base->race; @@ -246,7 +248,7 @@ namespace OutfitSystem for (auto it = armors.cbegin(); it != armors.cend(); ++it) { RE::TESObjectARMO* armor = *it; if (armor) { - if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { + if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) { // // We should only apply a shield's armor-addons if the player has // a shield equipped. @@ -358,12 +360,12 @@ namespace OutfitSystem // visitor to check for conflicts? // public: - virtual ReturnType Visit(RE::InventoryEntryData* data) override { - auto form = data->type; + virtual bool Visit(RE::InventoryEntryData* data) override { + auto form = data->object; if (form && form->formType == RE::FormType::Armor) { auto armor = reinterpret_cast(form); if (armor->TestBodyPartByIndex(this->conflictIndex)) { - auto em = RE::EquipManager::GetSingleton(); + auto em = RE::ActorEquipManager::GetSingleton(); // // TODO: The third argument to this call is meant to be a BaseExtraList*, // and Bethesda supplies one when calling from Unk_120. Can we get away @@ -376,10 +378,10 @@ namespace OutfitSystem // I was unable to stack the helmets with each other or with other helmets, // suggesting that the BaseExtraList may not be strictly necessary. // - em->UnEquipItem(this->target, form, nullptr, 1, nullptr, false, false, true, false, nullptr); + em->UnequipObject(this->target, form, nullptr, 1, nullptr, false, false, true, false, nullptr); } } - return ReturnType::kContinue; + return true; // True to continue visiting }; RE::Actor* target; @@ -448,7 +450,7 @@ namespace OutfitSystem pop(rcx); L(j_Exit); - xor(al, al); + xor_(al, al); L(j_Out); jmp(ptr[rip]); diff --git a/src/main.cpp b/src/main.cpp index 728b5a5..19b72ee 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,7 +9,6 @@ #include "OutfitSystem.h" #include "PlayerSkinning.h" - static PluginHandle g_pluginHandle = kPluginHandle_Invalid; static SKSEPapyrusInterface* g_Papyrus = nullptr; static SKSEMessagingInterface* g_Messaging = nullptr; @@ -42,7 +41,7 @@ bool SKSEPlugin_Query(const SKSEInterface* a_skse, PluginInfo* a_info) return false; } - if (a_skse->runtimeVersion != RUNTIME_VERSION_1_5_73) + if (a_skse->runtimeVersion != RUNTIME_VERSION_1_5_97) { _FATALERROR("[FATAL ERROR] Unsupported runtime version %08X!\n", a_skse->runtimeVersion); return false; @@ -112,7 +111,8 @@ bool SKSEPlugin_Load(const SKSEInterface* a_skse) } { // Papyrus registrations g_Papyrus = (SKSEPapyrusInterface*)a_skse->QueryInterface(kInterface_Papyrus); - _RegisterAndEchoPapyrus(OutfitSystem::RegisterPapyrus, "SkyrimOutfitSystemNativeFuncs"); + char name[] = "SkyrimOutfitSystemNativeFuncs"; + _RegisterAndEchoPapyrus(OutfitSystem::RegisterPapyrus, name); } return true; } diff --git a/vcpkg.json b/vcpkg.json new file mode 100644 index 0000000..ce781ff --- /dev/null +++ b/vcpkg.json @@ -0,0 +1,11 @@ +{ + "name": "skyrimoutfitsystem", + "version-string": "1.0.0", + "description": "Skyrim Outfit System for Skyrim Special Edition", + "supports": "windows & x64", + "dependencies": [ + "span-lite", + "spdlog" + ] + } + \ No newline at end of file