From 0f5f56a187aba7a1a62ab5e510d882531bd85a09 Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:07:29 +0300 Subject: [PATCH 1/6] preserve inventory order in AHuman::EquipFirearm This prevents AIs from messing up the inventory order whenever a player switches away from a unit while holding a tool or something. This has been bugging me for months. --- Source/Entities/AHuman.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 79cae5588b..9e0e086c3a 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -648,16 +648,19 @@ bool AHuman::EquipFirearm(bool doEquip) { // Found proper device to equip, so make the switch! if (pWeapon && pWeapon->IsWeapon()) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pWeapon); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -670,6 +673,7 @@ bool AHuman::EquipFirearm(bool doEquip) { if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } + } return true; From b294eab892a631dde7f959b961016a1cdeedcb5e Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Mon, 20 Oct 2025 18:32:23 +0300 Subject: [PATCH 2/6] preserve inventory order in AHuman::EquipNamedDevice too --- Source/Entities/AHuman.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 9e0e086c3a..c5b951223d 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -800,16 +800,19 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& // Found proper device to equip, so make the switch! if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order in case the player expects it to be some way. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + m_Inventory.pop_front(); + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pDevice); // Move the hand to a poisition so it looks like the new device was drawn from inventory From e9470dbcc0654a3cea5c41f099327bd3bf779744 Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:14:40 +0300 Subject: [PATCH 3/6] AHuman - preserve inventory order EVERYWHERE raaaaaah --- Source/Entities/AHuman.cpp | 53 +++++++++++++++++++++++--------------- 1 file changed, 32 insertions(+), 21 deletions(-) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index c5b951223d..545583ef00 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -654,7 +654,7 @@ bool AHuman::EquipFirearm(bool doEquip) { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } - // We want to preserve inventory order, so rotate it to the device in question. + // We want to preserve inventory order, so rotate to the device in question. std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to @@ -673,7 +673,6 @@ bool AHuman::EquipFirearm(bool doEquip) { if (m_DeviceSwitchSound) { m_DeviceSwitchSound->Play(m_Pos); } - } return true; @@ -698,10 +697,6 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { // Found proper device to equip, so make the switch! if (pDevice && pDevice->IsInGroup(group)) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -717,6 +712,12 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { } } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pDevice); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -753,16 +754,18 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro // Found proper device to equip, so make the switch! if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { m_pFGArm->GetHeldDevice()->Deactivate(); AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pFirearm); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -806,7 +809,7 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } - // We want to preserve inventory order in case the player expects it to be some way. + // We want to preserve inventory order, so rotate to the device in question. std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to @@ -851,9 +854,6 @@ bool AHuman::EquipThrowable(bool doEquip) { if (pThrown) // && pThrown->IsWeapon()) { if (doEquip) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -861,6 +861,12 @@ bool AHuman::EquipThrowable(bool doEquip) { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pThrown); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -975,9 +981,6 @@ bool AHuman::EquipShield() { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && pShield->IsShield()) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -985,6 +988,12 @@ bool AHuman::EquipShield() { AddToInventoryBack(m_pFGArm->RemoveAttachable(heldDevice)); } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pShield); // Move the hand to a poisition so it looks like the new device was drawn from inventory @@ -1034,10 +1043,6 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) { - // Erase the inventory entry containing the device we now have switched to - *itr = 0; - m_Inventory.erase(itr); - // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -1048,6 +1053,12 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { } } + // We want to preserve inventory order, so rotate it to the device in question. + std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + + // Erase the inventory entry containing the device we now have switched to + *m_Inventory.begin() = 0; + // Now put the device we were looking for and found into the hand m_pBGArm->SetHeldDevice(pShield); // Move the hand to a poisition so it looks like the new device was drawn from inventory From 22e9e846995d60af88032a1e3e408758e0481edf Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:29:08 +0300 Subject: [PATCH 4/6] AHuman.cpp - remove item in rotated inventory Forgot to put this down in the various places oops lmao --- Source/Entities/AHuman.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 545583ef00..33b3b42c3b 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -717,6 +717,7 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; + m_Inventory.pop_front(); // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pDevice); @@ -762,9 +763,11 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro // We want to preserve inventory order, so rotate it to the device in question. std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + m_Inventory.pop_front(); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; + m_Inventory.pop_front(); // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pFirearm); @@ -866,6 +869,7 @@ bool AHuman::EquipThrowable(bool doEquip) { // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; + m_Inventory.pop_front(); // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pThrown); @@ -993,6 +997,7 @@ bool AHuman::EquipShield() { // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; + m_Inventory.pop_front(); // Now put the device we were looking for and found into the hand m_pFGArm->SetHeldDevice(pShield); @@ -1055,6 +1060,7 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { // We want to preserve inventory order, so rotate it to the device in question. std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + m_Inventory.pop_front(); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; From b5a1b766f1205adc26247e70f75ff8e603c676b6 Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Mon, 20 Oct 2025 21:32:19 +0300 Subject: [PATCH 5/6] AHuman.cpp - remove item in rotated inventory PROPERLY gkljoiwjegoiwjoiuhbjfslkhgjwrpeso --- Source/Entities/AHuman.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 33b3b42c3b..707b4f8ce2 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -1060,10 +1060,10 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { // We want to preserve inventory order, so rotate it to the device in question. std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); - m_Inventory.pop_front(); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; + m_Inventory.pop_front(); // Now put the device we were looking for and found into the hand m_pBGArm->SetHeldDevice(pShield); From 6d0700c39906b64fc67dc9eb82f0f82dab0a9884 Mon Sep 17 00:00:00 2001 From: Architector #4 <23612841+Architector4@users.noreply.github.com> Date: Fri, 24 Oct 2025 18:50:58 +0300 Subject: [PATCH 6/6] AHuman.cpp - preserve inventory order WITHOUT CRASHING odksjhgvsdhgkjsdhghdsafoieh --- Source/Entities/AHuman.cpp | 42 ++++++++++++++++++++++++++++++-------- 1 file changed, 34 insertions(+), 8 deletions(-) diff --git a/Source/Entities/AHuman.cpp b/Source/Entities/AHuman.cpp index 707b4f8ce2..f84fecb1bb 100644 --- a/Source/Entities/AHuman.cpp +++ b/Source/Entities/AHuman.cpp @@ -648,6 +648,10 @@ bool AHuman::EquipFirearm(bool doEquip) { // Found proper device to equip, so make the switch! if (pWeapon && pWeapon->IsWeapon()) { if (doEquip) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); + // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -655,7 +659,7 @@ bool AHuman::EquipFirearm(bool doEquip) { } // We want to preserve inventory order, so rotate to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; @@ -697,6 +701,10 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { // Found proper device to equip, so make the switch! if (pDevice && pDevice->IsInGroup(group)) { if (doEquip) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); + // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -713,7 +721,7 @@ bool AHuman::EquipDeviceInGroup(std::string group, bool doEquip) { } // We want to preserve inventory order, so rotate it to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; @@ -755,6 +763,10 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro // Found proper device to equip, so make the switch! if (pFirearm && !pFirearm->NeedsReloading() && pFirearm->IsInGroup(group) && !pFirearm->IsInGroup(excludeGroup)) { if (doEquip) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); + // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { m_pFGArm->GetHeldDevice()->Deactivate(); @@ -762,7 +774,7 @@ bool AHuman::EquipLoadedFirearmInGroup(std::string group, std::string excludeGro } // We want to preserve inventory order, so rotate it to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); m_Inventory.pop_front(); // Erase the inventory entry containing the device we now have switched to @@ -806,6 +818,10 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& // Found proper device to equip, so make the switch! if (pDevice && (moduleName.empty() || pDevice->GetModuleName() == moduleName) && pDevice->GetPresetName() == presetName) { if (doEquip) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); + // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -813,9 +829,9 @@ bool AHuman::EquipNamedDevice(const std::string& moduleName, const std::string& } // We want to preserve inventory order, so rotate to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); - // Erase the inventory entry containing the device we now have switched to + // Erase the inventory entry containing the device. *m_Inventory.begin() = 0; m_Inventory.pop_front(); @@ -857,6 +873,9 @@ bool AHuman::EquipThrowable(bool doEquip) { if (pThrown) // && pThrown->IsWeapon()) { if (doEquip) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -865,7 +884,7 @@ bool AHuman::EquipThrowable(bool doEquip) { } // We want to preserve inventory order, so rotate it to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; @@ -985,6 +1004,9 @@ bool AHuman::EquipShield() { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && pShield->IsShield()) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pFGArm->GetHeldDevice()) { @@ -993,7 +1015,7 @@ bool AHuman::EquipShield() { } // We want to preserve inventory order, so rotate it to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0; @@ -1048,6 +1070,10 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { HeldDevice* pShield = dynamic_cast(*itr); // Found proper device to equip, so make the switch! if (pShield && (pShield->IsShield() || pShield->IsDualWieldable())) { + // The next code may cause reallocation, so we can't just use the same pointer. + // Store how far into the inventory the device is, memory wise. + size_t device_offset = itr - m_Inventory.begin(); + // Put back into the inventory what we had in our hands, if anything if (HeldDevice* heldDevice = m_pBGArm->GetHeldDevice()) { heldDevice->Deactivate(); @@ -1059,7 +1085,7 @@ bool AHuman::EquipShieldInBGArm(bool depositToFront) { } // We want to preserve inventory order, so rotate it to the device in question. - std::rotate(m_Inventory.begin(), itr, m_Inventory.end()); + std::rotate(m_Inventory.begin(), m_Inventory.begin() + device_offset, m_Inventory.end()); // Erase the inventory entry containing the device we now have switched to *m_Inventory.begin() = 0;