AnAtheistBear Posted November 28, 2024 Share Posted November 28, 2024 Here's what I have. The rest of the code can be found here: https://github.com/shavkacagarikia/ClassicHolsteredWeaponsSystem It needs to be compiled and packaged. F4NVSerialization.cpp _________________________ #include <fstream> #include "F4NVSerialization.h" #include "f4se/PluginAPI.h" #include "f4se/GameObjects.h" #include "f4se/GameReferences.h" #include "VisibleHolster.h" #include <array> #include <algorithm> namespace F4NVSerialization { std::array<VisibleHolster::WeaponPosition, 10> SavedWeaponPositionsArr{}; void RevertCallback(const F4SESerializationInterface * intfc) { // Clearing CHW serialization data. } void LoadCallback(const F4SESerializationInterface * intfc) { UInt32 type, version, length; VisibleHolster::ResetAllWeaponPos((*g_player)->GetActorRootNode(false)->GetAsNiNode()); while (intfc->GetNextRecordInfo(&type, &version, &length)) { switch (type) { case 'CHW': Load(intfc, InternalEventVersion::kCurrentVersion); break; } } } void LoadSavedPositionsData() { std::vector<VisibleHolster::WeaponPosition>* AttachPosVec = VisibleHolster::GetAttachPosVec(); for (size_t i = 0; i < SavedWeaponPositionsArr.size(); i++) { VisibleHolster::WeaponPosition currPos = SavedWeaponPositionsArr; for (size_t j = 0; j < AttachPosVec->size(); j++) { VisibleHolster::WeaponPosition* originalPos = &AttachPosVec->at(j); if (currPos.type == HolsterType::NotSet || !originalPos) { continue; } if (currPos.type == originalPos->type) { originalPos->posX = currPos.posX; originalPos->posY = currPos.posY; originalPos->posZ = currPos.posZ; originalPos->eulerAttitude = currPos.eulerAttitude; originalPos->eulerBank = currPos.eulerBank; originalPos->eulerHeading = currPos.eulerHeading; originalPos->ResetDataOnNode((*g_player)->GetActorRootNode(false)->GetAsNiNode()); } } } } void UpsertWeaponPosition(HolsterType type, float posX, float posY, float posZ, float eulerAttitude, float eulerBank, float eulerHeading) { bool found = false; for (size_t i = 0; i < SavedWeaponPositionsArr.size(); i++) { VisibleHolster::WeaponPosition* currPos = &SavedWeaponPositionsArr; if (currPos->type == HolsterType::NotSet) { continue; } if (currPos->type == type) { found = true; currPos->posX = posX; currPos->posY = posY; currPos->posZ = posZ; currPos->eulerAttitude = eulerAttitude; currPos->eulerBank = eulerBank; currPos->eulerHeading = eulerHeading; currPos->ResetDataOnNode((*g_player)->GetActorRootNode(false)->GetAsNiNode()); break; } } if (!found && type != HolsterType::NotSet) { VisibleHolster::WeaponPosition newPos = {}; newPos.type = type; newPos.posX = posX; newPos.posY = posY; newPos.posZ = posZ; newPos.eulerAttitude = eulerAttitude; newPos.eulerBank = eulerBank; newPos.eulerHeading = eulerHeading; newPos.ResetDataOnNode((*g_player)->GetActorRootNode(false)->GetAsNiNode()); int index = static_cast<int>(type) - 1; SavedWeaponPositionsArr[index] = newPos; } } bool Load(const F4SESerializationInterface * intfc, UInt32 version) { if (!Serialization::ReadData(intfc, &SavedWeaponPositionsArr)) { _MESSAGE("Cannot Load SavedWeaponPositionsArr"); return false; } LoadSavedPositionsData(); return true; } void SaveCallback(const F4SESerializationInterface * intfc) { Save(intfc, 'CHW', InternalEventVersion::kCurrentVersion); } bool Save(const F4SESerializationInterface * intfc, UInt32 type, UInt32 version) { intfc->OpenRecord(type, version); if (!intfc->WriteRecordData(&SavedWeaponPositionsArr, sizeof(SavedWeaponPositionsArr))) { _MESSAGE("Error writing SavedWeaponPositionsArr data"); return false; } return true; } } _________________________ VisibleHolster.cpp _________________________ #include "VisibleHolster.h" #include "f4se/GameReferences.h" #include "f4se/NiNodes.h" #include <vector> namespace VisibleHolster { std::vector<WeaponPosition> attachPosVec; void ResetAllWeaponPos(NiNode* rootNode) { if (!rootNode) return; for (auto& weaponPos : attachPosVec) { weaponPos.posX = 0.0f; weaponPos.posY = 0.0f; weaponPos.posZ = 0.0f; weaponPos.eulerAttitude = 0.0f; weaponPos.eulerBank = 0.0f; weaponPos.eulerHeading = 0.0f; weaponPos.ResetDataOnNode(rootNode); } } std::vector<WeaponPosition>* GetAttachPosVec() { return &attachPosVec; } void WeaponPosition::ResetDataOnNode(NiNode* rootNode) { if (!rootNode || type == HolsterType::NotSet) return; NiNode* weaponNode = rootNode->GetObjectByName(typeToNodeName(type)); if (!weaponNode) return; weaponNode->m_localTransform.pos.x = posX; weaponNode->m_localTransform.pos.y = posY; weaponNode->m_localTransform.pos.z = posZ; weaponNode->m_localTransform.rot.SetEuler(eulerAttitude, eulerBank, eulerHeading); weaponNode->UpdateWorldData(0.0f); } const char* WeaponPosition::typeToNodeName(HolsterType type) { switch (type) { case HolsterType::Pistol: return "PistolHolster"; case HolsterType::Rifle: return "RifleHolster"; case HolsterType::Shotgun: return "ShotgunHolster"; case HolsterType::Knife: return "KnifeHolster"; default: return ""; } } } _________________________ PapyrusFunctions.cpp _________________________ #include "PapyrusFunctions.h" #include "VisibleHolster.h" #include "f4se/PapyrusNativeFunctions.h" namespace PapyrusFunctions { bool RegisterFunctions(VMClassRegistry* registry) { registry->RegisterFunction( new NativeFunction5<StaticFunctionTag, void, SInt32, float, float, float, SInt32>( "UpsertWeaponPosition", "ClassicHolsteredWeaponsSystem", UpsertWeaponPosition, registry ) ); registry->RegisterFunction( new NativeFunction1<StaticFunctionTag, void, SInt32>( "ResetAllWeaponPositions", "ClassicHolsteredWeaponsSystem", ResetAllWeaponPositions, registry ) ); return true; } void UpsertWeaponPosition(StaticFunctionTag*, SInt32 holsterType, float posX, float posY, float posZ, SInt32 rotationMode) { using namespace VisibleHolster; auto type = static_cast<HolsterType>(holsterType); float eulerAttitude = 0.0f, eulerBank = 0.0f, eulerHeading = 0.0f; if (rotationMode == 1) { eulerAttitude = 0.5f; // Adjust as needed for different rotation types } else if (rotationMode == 2) { eulerBank = 0.5f; } else if (rotationMode == 3) { eulerHeading = 0.5f; } UpsertWeaponPosition(type, posX, posY, posZ, eulerAttitude, eulerBank, eulerHeading); } void ResetAllWeaponPositions(StaticFunctionTag*) { auto rootNode = (*g_player)->GetActorRootNode(false)->GetAsNiNode(); VisibleHolster::ResetAllWeaponPos(rootNode); } } _________________________ Positioner.cpp _________________________ #include "Positioner.h" #include "VisibleHolster.h" #include "f4se/GameReferences.h" #include "f4se/NiNodes.h" #include <cmath> namespace Positioner { void PositionWeapon(NiNode* rootNode, VisibleHolster::WeaponPosition& position) { if (!rootNode) return; NiNode* weaponNode = rootNode->GetObjectByName(VisibleHolster::WeaponPosition::typeToNodeName(position.type)); if (!weaponNode) return; weaponNode->m_localTransform.pos.x = position.posX; weaponNode->m_localTransform.pos.y = position.posY; weaponNode->m_localTransform.pos.z = position.posZ; weaponNode->m_localTransform.rot.SetEuler(position.eulerAttitude, position.eulerBank, position.eulerHeading); weaponNode->UpdateWorldData(0.0f); } void ApplyWeaponPositionsToPlayer() { NiNode* rootNode = (*g_player)->GetActorRootNode(false)->GetAsNiNode(); if (!rootNode) return; for (auto& position : VisibleHolster::GetAttachPosVec()) { if (position.type != HolsterType::NotSet) { PositionWeapon(rootNode, position); } } } void AdjustWeaponPosition(VisibleHolster::WeaponPosition& position, float deltaX, float deltaY, float deltaZ, float deltaAttitude, float deltaBank, float deltaHeading) { position.posX += deltaX; position.posY += deltaY; position.posZ += deltaZ; position.eulerAttitude += deltaAttitude; position.eulerBank += deltaBank; position.eulerHeading += deltaHeading; } } _________________________ AttachHandler.cpp _________________________ #include "AttachHandler.h" #include "VisibleHolster.h" #include "f4se/GameReferences.h" #include "f4se/NiNodes.h" namespace AttachHandler { bool AttachWeaponToHolster(NiNode* rootNode, VisibleHolster::WeaponPosition& position) { if (!rootNode) return false; NiNode* weaponNode = rootNode->GetObjectByName(VisibleHolster::WeaponPosition::typeToNodeName(position.type)); if (!weaponNode) return false; weaponNode->m_localTransform.pos.x = position.posX; weaponNode->m_localTransform.pos.y = position.posY; weaponNode->m_localTransform.pos.z = position.posZ; weaponNode->m_localTransform.rot.SetEuler(position.eulerAttitude, position.eulerBank, position.eulerHeading); weaponNode->UpdateWorldData(0.0f); return true; } bool DetachWeaponFromHolster(NiNode* rootNode, HolsterType type) { if (!rootNode) return false; NiNode* weaponNode = rootNode->GetObjectByName(VisibleHolster::WeaponPosition::typeToNodeName(type)); if (!weaponNode) return false; // Reset weapon position (e.g., hide or reset to default) weaponNode->m_localTransform.pos = NiPoint3(0.0f, 0.0f, 0.0f); weaponNode->m_localTransform.rot.SetEuler(0.0f, 0.0f, 0.0f); weaponNode->UpdateWorldData(0.0f); return true; } void ProcessWeaponAttachment(HolsterType type, bool attach, float posX, float posY, float posZ, float eulerAttitude, float eulerBank, float eulerHeading) { NiNode* rootNode = (*g_player)->GetActorRootNode(false)->GetAsNiNode(); if (!rootNode) return; VisibleHolster::WeaponPosition position = { type, posX, posY, posZ, eulerAttitude, eulerBank, eulerHeading }; if (attach) { AttachWeaponToHolster(rootNode, position); } else { DetachWeaponFromHolster(rootNode, type); } } } _________________________ ScaleformF4NV.cpp _________________________ #include "ScaleformF4NV.h" #include "VisibleHolster.h" #include "f4se/ScaleformCallbacks.h" #include "f4se/ScaleformMovie.h" #include "f4se/ScaleformValue.h" namespace ScaleformF4NV { bool GetHolsterPosition(GFxMovieView* view, GFxValue* result, VisibleHolster::WeaponPosition position) { if (!view || !result) return false; GFxValue posX, posY, posZ; posX.SetNumber(position.posX); posY.SetNumber(position.posY); posZ.SetNumber(position.posZ); result->SetMember("posX", &posX); result->SetMember("posY", &posY); result->SetMember("posZ", &posZ); GFxValue eulerAttitude, eulerBank, eulerHeading; eulerAttitude.SetNumber(position.eulerAttitude); eulerBank.SetNumber(position.eulerBank); eulerHeading.SetNumber(position.eulerHeading); result->SetMember("eulerAttitude", &eulerAttitude); result->SetMember("eulerBank", &eulerBank); result->SetMember("eulerHeading", &eulerHeading); return true; } void RegisterScaleform(GFxMovieView* view, GFxValue* f4nvObj) { GFxValue holsterPositions; view->CreateObject(&holsterPositions); for (const auto& position : VisibleHolster::GetAttachPosVec()) { GFxValue holsterData; view->CreateObject(&holsterData); if (GetHolsterPosition(view, &holsterData, position)) { holsterPositions.SetMember(VisibleHolster::WeaponPosition::typeToNodeName(position.type), &holsterData); } } f4nvObj->SetMember("holsterPositions", &holsterPositions); } bool RegisterScaleformFunctions(GFxMovieView* view, GFxValue* f4nvObj) { if (!view || !f4nvObj) return false; RegisterScaleform(view, f4nvObj); return true; } } _________________________ 2 Link to comment Share on other sites More sharing options...
GlennCroft Posted December 23, 2024 Share Posted December 23, 2024 Thanks for sharing, hopefully someone will take this and update the mod for ng players. Link to comment Share on other sites More sharing options...
AnAtheistBear Posted December 23, 2024 Author Share Posted December 23, 2024 I actually just tried it yesterday. It's not right. VB22 was shooting out too many errors... I'll keep working on it, especially now that I have a week off for the holidays. Link to comment Share on other sites More sharing options...
Recommended Posts