|
1 | 1 | #include <Services/InventoryService.h> |
2 | 2 |
|
3 | 3 | #include <cstdlib> |
| 4 | +#include <TiltedCore/Stl.hpp> |
4 | 5 |
|
5 | 6 | #include <Messages/RequestObjectInventoryChanges.h> |
6 | 7 | #include <Messages/NotifyObjectInventoryChanges.h> |
|
15 | 16 | #include <Events/InventoryChangeEvent.h> |
16 | 17 | #include <Events/EquipmentChangeEvent.h> |
17 | 18 |
|
| 19 | +#include <Components.h> |
18 | 20 | #include <World.h> |
19 | 21 | #include <Games/Skyrim/Interface/UI.h> |
20 | 22 | #include <PlayerCharacter.h> |
@@ -44,6 +46,7 @@ InventoryService::InventoryService(World& aWorld, entt::dispatcher& aDispatcher, |
44 | 46 |
|
45 | 47 | void InventoryService::OnUpdate(const UpdateEvent& acUpdateEvent) noexcept |
46 | 48 | { |
| 49 | + ProcessPendingEquipment(); |
47 | 50 | RunWeaponStateUpdates(); |
48 | 51 | RunNakedNPCBugChecks(); |
49 | 52 | } |
@@ -252,6 +255,33 @@ void InventoryService::OnNotifyEquipmentChanges(const NotifyEquipmentChanges& ac |
252 | 255 | return; |
253 | 256 | } |
254 | 257 |
|
| 258 | + if (!pActor->GetNiNode()) |
| 259 | + { |
| 260 | + auto view = m_world.view<FormIdComponent>(); |
| 261 | + const auto itor = std::find_if(std::begin(view), std::end(view), [formId = pActor->formID, view](entt::entity entity) { return view.get<FormIdComponent>(entity).Id == formId; }); |
| 262 | + |
| 263 | + if (itor != std::end(view)) |
| 264 | + { |
| 265 | + auto* pPending = m_world.try_get<PendingEquipmentComponent>(*itor); |
| 266 | + if (!pPending) |
| 267 | + pPending = &m_world.emplace<PendingEquipmentComponent>(*itor); |
| 268 | + |
| 269 | + pPending->PendingChanges.push_back(acMessage); |
| 270 | + spdlog::debug("Queued equipment change for actor {:X} until 3D is ready", pActor->formID); |
| 271 | + } |
| 272 | + else |
| 273 | + { |
| 274 | + spdlog::warn("{}: could not queue equipment change, entity not found for form id {:X}", __FUNCTION__, pActor->formID); |
| 275 | + } |
| 276 | + |
| 277 | + return; |
| 278 | + } |
| 279 | + |
| 280 | + ApplyEquipmentChange(pActor, acMessage); |
| 281 | +} |
| 282 | + |
| 283 | +void InventoryService::ApplyEquipmentChange(Actor* pActor, const NotifyEquipmentChanges& acMessage) noexcept |
| 284 | +{ |
255 | 285 | auto& modSystem = World::Get().GetModSystem(); |
256 | 286 |
|
257 | 287 | uint32_t itemId = modSystem.GetGameId(acMessage.ItemId); |
@@ -326,6 +356,30 @@ void InventoryService::OnNotifyEquipmentChanges(const NotifyEquipmentChanges& ac |
326 | 356 | } |
327 | 357 | } |
328 | 358 |
|
| 359 | +void InventoryService::ProcessPendingEquipment() noexcept |
| 360 | +{ |
| 361 | + auto view = m_world.view<FormIdComponent, PendingEquipmentComponent>(); |
| 362 | + TiltedPhoques::Vector<entt::entity> toClear; |
| 363 | + |
| 364 | + for (auto entity : view) |
| 365 | + { |
| 366 | + auto& formIdComponent = view.get<FormIdComponent>(entity); |
| 367 | + auto& pending = view.get<PendingEquipmentComponent>(entity); |
| 368 | + |
| 369 | + Actor* pActor = Cast<Actor>(TESForm::GetById(formIdComponent.Id)); |
| 370 | + if (!pActor || !pActor->GetNiNode()) |
| 371 | + continue; |
| 372 | + |
| 373 | + for (const auto& change : pending.PendingChanges) |
| 374 | + ApplyEquipmentChange(pActor, change); |
| 375 | + |
| 376 | + toClear.push_back(entity); |
| 377 | + } |
| 378 | + |
| 379 | + for (auto entity : toClear) |
| 380 | + m_world.remove<PendingEquipmentComponent>(entity); |
| 381 | +} |
| 382 | + |
329 | 383 | void InventoryService::RunWeaponStateUpdates() noexcept |
330 | 384 | { |
331 | 385 | if (!m_transport.IsConnected()) |
|
0 commit comments