Fix shutdown hangs, bank bag icons/drag-drop, loading screen progress, and login spawn

- Fix shutdown hang: skip vmaDestroyAllocator (walked thousands of allocations),
  replace unsafe pthread_timedjoin_np with plain join + early-exit checks in workers
- Bank window: full icon rendering, click-and-hold pickup (0.10s), drag-drop for
  all bank slots including bank bag equip slots, same-slot drop detection
- Loading screen: process one tile per frame for live progress updates
- Camera reset: trust server position in online mode to avoid spawning under WMOs
- Fix PLAYER_BYTES/PLAYER_BYTES_2 field indices, preserve purchasedBankBagSlots
  across inventory rebuilds, fix bank slot purchase result codes
This commit is contained in:
Kelsi 2026-02-26 13:38:29 -08:00
parent 804b947203
commit a559d5944b
14 changed files with 489 additions and 146 deletions

View file

@ -304,6 +304,57 @@ void InventoryScreen::pickupFromEquipment(game::Inventory& inv, game::EquipSlot
inventoryDirty = true;
}
void InventoryScreen::pickupFromBank(game::Inventory& inv, int bankIndex) {
const auto& slot = inv.getBankSlot(bankIndex);
if (slot.empty()) return;
holdingItem = true;
heldItem = slot.item;
heldSource = HeldSource::BANK;
heldBankIndex = bankIndex;
heldBackpackIndex = -1;
heldBagIndex = -1;
heldBagSlotIndex = -1;
heldBankBagIndex = -1;
heldBankBagSlotIndex = -1;
heldEquipSlot = game::EquipSlot::NUM_SLOTS;
inv.clearBankSlot(bankIndex);
inventoryDirty = true;
}
void InventoryScreen::pickupFromBankBag(game::Inventory& inv, int bagIndex, int slotIndex) {
const auto& slot = inv.getBankBagSlot(bagIndex, slotIndex);
if (slot.empty()) return;
holdingItem = true;
heldItem = slot.item;
heldSource = HeldSource::BANK_BAG;
heldBankBagIndex = bagIndex;
heldBankBagSlotIndex = slotIndex;
heldBankIndex = -1;
heldBackpackIndex = -1;
heldBagIndex = -1;
heldBagSlotIndex = -1;
heldEquipSlot = game::EquipSlot::NUM_SLOTS;
inv.clearBankBagSlot(bagIndex, slotIndex);
inventoryDirty = true;
}
void InventoryScreen::pickupFromBankBagEquip(game::Inventory& inv, int bagIndex) {
const auto& slot = inv.getBankBagItem(bagIndex);
if (slot.empty()) return;
holdingItem = true;
heldItem = slot.item;
heldSource = HeldSource::BANK_BAG_EQUIP;
heldBankBagIndex = bagIndex;
heldBankBagSlotIndex = -1;
heldBankIndex = -1;
heldBackpackIndex = -1;
heldBagIndex = -1;
heldBagSlotIndex = -1;
heldEquipSlot = game::EquipSlot::NUM_SLOTS;
inv.setBankBagItem(bagIndex, game::ItemDef{});
inventoryDirty = true;
}
void InventoryScreen::placeInBackpack(game::Inventory& inv, int index) {
if (!holdingItem) return;
if (gameHandler_) {
@ -319,6 +370,13 @@ void InventoryScreen::placeInBackpack(game::Inventory& inv, int index) {
srcSlot = static_cast<uint8_t>(heldBagSlotIndex);
} else if (heldSource == HeldSource::EQUIPMENT) {
srcSlot = static_cast<uint8_t>(heldEquipSlot);
} else if (heldSource == HeldSource::BANK && heldBankIndex >= 0) {
srcSlot = static_cast<uint8_t>(39 + heldBankIndex);
} else if (heldSource == HeldSource::BANK_BAG && heldBankBagIndex >= 0) {
srcBag = static_cast<uint8_t>(67 + heldBankBagIndex);
srcSlot = static_cast<uint8_t>(heldBankBagSlotIndex);
} else if (heldSource == HeldSource::BANK_BAG_EQUIP && heldBankBagIndex >= 0) {
srcSlot = static_cast<uint8_t>(67 + heldBankBagIndex);
} else {
cancelPickup(inv);
return;
@ -357,6 +415,13 @@ void InventoryScreen::placeInBag(game::Inventory& inv, int bagIndex, int slotInd
srcSlot = static_cast<uint8_t>(heldBagSlotIndex);
} else if (heldSource == HeldSource::EQUIPMENT) {
srcSlot = static_cast<uint8_t>(heldEquipSlot);
} else if (heldSource == HeldSource::BANK && heldBankIndex >= 0) {
srcSlot = static_cast<uint8_t>(39 + heldBankIndex);
} else if (heldSource == HeldSource::BANK_BAG && heldBankBagIndex >= 0) {
srcBag = static_cast<uint8_t>(67 + heldBankBagIndex);
srcSlot = static_cast<uint8_t>(heldBankBagSlotIndex);
} else if (heldSource == HeldSource::BANK_BAG_EQUIP && heldBankBagIndex >= 0) {
srcSlot = static_cast<uint8_t>(67 + heldBankBagIndex);
} else {
cancelPickup(inv);
return;
@ -417,6 +482,11 @@ void InventoryScreen::placeInEquipment(game::Inventory& inv, game::EquipSlot slo
srcSlot = static_cast<uint8_t>(heldBagSlotIndex);
} else if (heldSource == HeldSource::EQUIPMENT && heldEquipSlot != game::EquipSlot::NUM_SLOTS) {
srcSlot = static_cast<uint8_t>(heldEquipSlot);
} else if (heldSource == HeldSource::BANK && heldBankIndex >= 0) {
srcSlot = static_cast<uint8_t>(39 + heldBankIndex);
} else if (heldSource == HeldSource::BANK_BAG && heldBankBagIndex >= 0) {
srcBag = static_cast<uint8_t>(67 + heldBankBagIndex);
srcSlot = static_cast<uint8_t>(heldBankBagSlotIndex);
} else {
cancelPickup(inv);
return;
@ -486,6 +556,24 @@ void InventoryScreen::cancelPickup(game::Inventory& inv) {
} else {
inv.addItem(heldItem);
}
} else if (heldSource == HeldSource::BANK && heldBankIndex >= 0) {
if (inv.getBankSlot(heldBankIndex).empty()) {
inv.setBankSlot(heldBankIndex, heldItem);
} else {
inv.addItem(heldItem);
}
} else if (heldSource == HeldSource::BANK_BAG && heldBankBagIndex >= 0 && heldBankBagSlotIndex >= 0) {
if (inv.getBankBagSlot(heldBankBagIndex, heldBankBagSlotIndex).empty()) {
inv.setBankBagSlot(heldBankBagIndex, heldBankBagSlotIndex, heldItem);
} else {
inv.addItem(heldItem);
}
} else if (heldSource == HeldSource::BANK_BAG_EQUIP && heldBankBagIndex >= 0) {
if (inv.getBankBagItem(heldBankBagIndex).empty()) {
inv.setBankBagItem(heldBankBagIndex, heldItem);
} else {
inv.addItem(heldItem);
}
} else {
inv.addItem(heldItem);
}
@ -554,9 +642,22 @@ void InventoryScreen::dropIntoBankSlot(game::GameHandler& /*gh*/, uint8_t dstBag
srcSlot = static_cast<uint8_t>(heldBagSlotIndex);
} else if (heldSource == HeldSource::EQUIPMENT) {
srcSlot = static_cast<uint8_t>(heldEquipSlot);
} else if (heldSource == HeldSource::BANK && heldBankIndex >= 0) {
srcSlot = static_cast<uint8_t>(39 + heldBankIndex);
} else if (heldSource == HeldSource::BANK_BAG && heldBankBagIndex >= 0) {
srcBag = static_cast<uint8_t>(67 + heldBankBagIndex);
srcSlot = static_cast<uint8_t>(heldBankBagSlotIndex);
} else if (heldSource == HeldSource::BANK_BAG_EQUIP && heldBankBagIndex >= 0) {
srcSlot = static_cast<uint8_t>(67 + heldBankBagIndex);
} else {
return;
}
// Same source and dest — just cancel pickup (restore item locally).
// Server ignores same-slot swaps so no rebuild would run, losing the item data.
if (srcBag == dstBag && srcSlot == dstSlot) {
cancelPickup(gameHandler_->getInventory());
return;
}
gameHandler_->swapContainerItems(srcBag, srcSlot, dstBag, dstSlot);
holdingItem = false;
inventoryDirty = true;