AnAtheistBear Posted Thursday at 10:49 PM Share Posted Thursday at 10:49 PM 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; } } _________________________ 1 Link to comment Share on other sites More sharing options...
Recommended Posts