Finally got it to build, with much beating
This commit is contained in:
parent
52259574da
commit
230e5dd65c
9 changed files with 166 additions and 87 deletions
6
.gitignore
vendored
6
.gitignore
vendored
|
|
@ -333,4 +333,8 @@ ASALocalRun/
|
|||
# Local History for Visual Studio
|
||||
.localhistory/
|
||||
|
||||
x64
|
||||
x64
|
||||
dependencies/skse64/src/common/x64_v142
|
||||
executables
|
||||
vcpkg_installed
|
||||
x64_v142
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -53,6 +53,14 @@
|
|||
<PostBuildEventUseInBuild>false</PostBuildEventUseInBuild>
|
||||
<IncludePath>dependencies\CommonLibSSE\include;include;dependencies\skse64\src;dependencies\skse64\src\skse64;$(IncludePath)</IncludePath>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Label="Vcpkg" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<VcpkgEnableManifest>true</VcpkgEnableManifest>
|
||||
<VcpkgUseStatic>true</VcpkgUseStatic>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<Optimization>Disabled</Optimization>
|
||||
|
|
@ -175,11 +183,13 @@
|
|||
<ProjectReference Include="dependencies\CommonLibSSE\CommonLibSSE.vcxproj">
|
||||
<Project>{c1af9204-ee2d-421b-b11e-1d70d8acc11f}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="dependencies\skse64\src\skse64\skse64\skse64.vcxproj">
|
||||
<Project>{7028b79c-06e3-4d9a-b38c-1dc3680b1bdb}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="dependencies\skse64\src\skse64\skse64_common\skse64_common.vcxproj">
|
||||
<Project>{5fd1c08d-db80-480c-a1c6-f0920005cd13}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="ExtensionTargets" />
|
||||
</Project>
|
||||
|
|
@ -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 {
|
||||
|
|
|
|||
|
|
@ -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<RE::TESObjectARMO*>(DYNAMIC_CAST(LookupFormByID(fixedID), TESForm, TESObjectARMO));
|
||||
auto armor = reinterpret_cast<RE::TESObjectARMO*>(Runtime_DynamicCast((void*) LookupFormByID(fixedID), RTTI_TESForm, RTTI_TESObjectARMO));
|
||||
if (armor)
|
||||
this->armors.insert(armor);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<RE::TESObjectARMO*> GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) {
|
||||
VMResultArray<TESObjectARMO*> GetCarriedArmor(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) {
|
||||
VMResultArray<RE::TESObjectARMO*> result;
|
||||
auto target = (RE::Actor*) (target_skse);
|
||||
if (target == nullptr) {
|
||||
registry->LogError("Cannot retrieve data for a None actor.", stackId);
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> 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<RE::TESObjectARMO*>(form));
|
||||
return ReturnType::kContinue;
|
||||
return true;
|
||||
};
|
||||
|
||||
VMResultArray<RE::TESObjectARMO*>& list;
|
||||
|
|
@ -53,13 +61,20 @@
|
|||
_Visitor visitor(result);
|
||||
inventory->ExecuteVisitor(&visitor);
|
||||
}
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> converted_result;
|
||||
converted_result.reserve(result.size());
|
||||
for (const auto ptr : result) {
|
||||
converted_result.push_back((TESObjectARMO*)ptr);
|
||||
}
|
||||
return converted_result;
|
||||
}
|
||||
VMResultArray<RE::TESObjectARMO*> GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, RE::Actor* target) {
|
||||
VMResultArray<TESObjectARMO*> GetWornItems(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, Actor* target_skse) {
|
||||
VMResultArray<RE::TESObjectARMO*> result;
|
||||
auto target = (RE::Actor*) (target_skse);
|
||||
if (target == nullptr) {
|
||||
registry->LogError("Cannot retrieve data for a None actor.", stackId);
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> 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<RE::TESObjectARMO*>(form));
|
||||
return ReturnType::kContinue;
|
||||
return true;
|
||||
};
|
||||
|
||||
VMResultArray<RE::TESObjectARMO*>& list;
|
||||
|
|
@ -84,11 +99,17 @@
|
|||
_Visitor visitor(result);
|
||||
inventory->ExecuteVisitorOnWorn(&visitor);
|
||||
}
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> 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<RE::TESObjectARMO*>(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<RE::TESObjectARMO*> GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<TESObjectARMO*> GetForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<RE::TESObjectARMO*> result;
|
||||
auto& list = data.armors;
|
||||
for (auto it = list.begin(); it != list.end(); it++)
|
||||
result.push_back(*it);
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> converted_result;
|
||||
converted_result.reserve(result.size());
|
||||
for (const auto ptr : result) {
|
||||
converted_result.push_back((TESObjectARMO*)ptr);
|
||||
}
|
||||
return converted_result;
|
||||
}
|
||||
VMResultArray<BSFixedString> GetNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<BSFixedString> 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<RE::TESObjectARMO*> GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<TESObjectARMO*> GetArmorForms(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<RE::TESObjectARMO*> result;
|
||||
auto& list = data.armors;
|
||||
for (auto it = list.begin(); it != list.end(); it++)
|
||||
result.push_back(*it);
|
||||
return result;
|
||||
VMResultArray<TESObjectARMO*> converted_result;
|
||||
converted_result.reserve(result.size());
|
||||
for (const auto ptr : result) {
|
||||
converted_result.push_back((TESObjectARMO*)ptr);
|
||||
}
|
||||
return converted_result;
|
||||
}
|
||||
VMResultArray<BSFixedString> GetArmorNames(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*) {
|
||||
VMResultArray<BSFixedString> 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<RE::TESObjectARMO*> GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) {
|
||||
VMResultArray<TESObjectARMO*> GetOutfitContents(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name) {
|
||||
VMResultArray<RE::TESObjectARMO*> 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<TESObjectARMO*> 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<uint32_t>(mask) & static_cast<uint32_t>(candidateMask)) != static_cast<uint32_t>(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<RE::TESObjectARMO*> armors) {
|
||||
void OverwriteOutfit(VMClassRegistry* registry, UInt32 stackId, StaticFunctionTag*, BSFixedString name, VMArray<TESObjectARMO*> armors_skse) {
|
||||
auto& service = ArmorAddonOverrideService::GetInstance();
|
||||
// Convert input array.
|
||||
VMResultArray<RE::TESObjectARMO*> 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<StaticFunctionTag, VMResultArray<RE::TESObjectARMO*>, RE::Actor*>(
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, VMResultArray<TESObjectARMO*>, Actor*>(
|
||||
"GetCarriedArmor",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
GetCarriedArmor,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, VMResultArray<RE::TESObjectARMO*>, RE::Actor*>(
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, VMResultArray<TESObjectARMO*>, Actor*>(
|
||||
"GetWornItems",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
GetWornItems,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, void, RE::Actor*>(
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, void, Actor*>(
|
||||
"RefreshArmorFor",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
RefreshArmorFor,
|
||||
|
|
@ -536,7 +588,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
|
|||
ArmorFormSearchUtils::Prep,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction0<StaticFunctionTag, VMResultArray<RE::TESObjectARMO*>>(
|
||||
registry->RegisterFunction(new NativeFunction0<StaticFunctionTag, VMResultArray<TESObjectARMO*>>(
|
||||
"GetArmorSearchResultForms",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
ArmorFormSearchUtils::GetForms,
|
||||
|
|
@ -562,7 +614,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
|
|||
BodySlotListing::Prep,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction0<StaticFunctionTag, VMResultArray<RE::TESObjectARMO*>>(
|
||||
registry->RegisterFunction(new NativeFunction0<StaticFunctionTag, VMResultArray<TESObjectARMO*>>(
|
||||
"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<StaticFunctionTag, VMResultArray<BSFixedString>, VMArray<BSFixedString>, VMArray<RE::TESObjectARMO*>, bool>(
|
||||
registry->RegisterFunction(new NativeFunction3<StaticFunctionTag, VMResultArray<BSFixedString>, VMArray<BSFixedString>, VMArray<TESObjectARMO*>, bool>(
|
||||
"NaturalSortPairArmor_ASCII",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
StringSorts::NaturalSortPair_ASCII<RE::TESObjectARMO*>,
|
||||
StringSorts::NaturalSortPair_ASCII<TESObjectARMO*>,
|
||||
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<StaticFunctionTag, void, BSFixedString, RE::TESObjectARMO*>(
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, BSFixedString, TESObjectARMO*>(
|
||||
"AddArmorToOutfit",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
AddArmorToOutfit,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, bool, RE::TESObjectARMO*, BSFixedString>(
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, bool, TESObjectARMO*, BSFixedString>(
|
||||
"ArmorConflictsWithOutfit",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
ArmorConflictsWithOutfit,
|
||||
|
|
@ -644,7 +696,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
|
|||
DeleteOutfit,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, VMResultArray<RE::TESObjectARMO*>, BSFixedString>(
|
||||
registry->RegisterFunction(new NativeFunction1<StaticFunctionTag, VMResultArray<TESObjectARMO*>, BSFixedString>(
|
||||
"GetOutfitContents",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
GetOutfitContents,
|
||||
|
|
@ -668,13 +720,13 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
|
|||
ListOutfits,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, BSFixedString, RE::TESObjectARMO*>(
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, BSFixedString, TESObjectARMO*>(
|
||||
"RemoveArmorFromOutfit",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
RemoveArmorFromOutfit,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, RE::TESObjectARMO*, BSFixedString>(
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, TESObjectARMO*, BSFixedString>(
|
||||
"RemoveConflictingArmorsFrom",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
RemoveConflictingArmorsFrom,
|
||||
|
|
@ -692,7 +744,7 @@ bool OutfitSystem::RegisterPapyrus(VMClassRegistry* registry) {
|
|||
OutfitExists,
|
||||
registry
|
||||
));
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, BSFixedString, VMArray<RE::TESObjectARMO*>>(
|
||||
registry->RegisterFunction(new NativeFunction2<StaticFunctionTag, void, BSFixedString, VMArray<TESObjectARMO*>>(
|
||||
"OverwriteOutfit",
|
||||
"SkyrimOutfitSystemNativeFuncs",
|
||||
OverwriteOutfit,
|
||||
|
|
|
|||
|
|
@ -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<RE::TESObjectARMO*>(form);
|
||||
if ((armor->flags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
|
||||
if ((armor->formFlags & RE::TESObjectARMO::RecordFlags::kShield) != 0) {
|
||||
this->mask |= static_cast<UInt32>(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<RE::TESObjectARMO*>(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<RE::TESNPC*>(DYNAMIC_CAST(target->baseForm, TESForm, TESNPC));
|
||||
auto base = reinterpret_cast<RE::TESNPC*>(Runtime_DynamicCast(static_cast<RE::TESForm*>(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<RE::TESObjectARMO*>(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]);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
11
vcpkg.json
Normal file
11
vcpkg.json
Normal file
|
|
@ -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"
|
||||
]
|
||||
}
|
||||
|
||||
Loading…
Add table
Add a link
Reference in a new issue