2
0
mirror of https://github.com/AxioDL/metaforce.git synced 2025-05-13 14:31:20 +00:00
metaforce/Runtime/CResFactory.cpp
Lioncash 0a47e623fd CResFactory: Resolve use-after-move in AddToLoadList()
The behavior on the right hand side would occur before the actual
assignment, making the tag value invalidated. Instead, we copy the tag
before the move is performed to keep the data valid when inserting it
into the map.
2020-03-07 03:56:16 -05:00

116 lines
4.0 KiB
C++

#include "Runtime/CResFactory.hpp"
#include "Runtime/CSimplePool.hpp"
#include "Runtime/CStopwatch.hpp"
namespace urde {
static logvisor::Module Log("CResFactory");
void CResFactory::AddToLoadList(SLoadingData&& data) {
const SObjectTag tag = data.x0_tag;
m_loadMap.insert_or_assign(tag, m_loadList.insert(m_loadList.end(), std::move(data)));
}
CFactoryFnReturn CResFactory::BuildSync(const SObjectTag& tag, const CVParamTransfer& xfer, CObjectReference* selfRef) {
CFactoryFnReturn ret;
if (x5c_factoryMgr.CanMakeMemory(tag)) {
std::unique_ptr<uint8_t[]> data;
int size = 0;
x4_loader.LoadMemResourceSync(tag, data, &size);
if (size)
ret = x5c_factoryMgr.MakeObjectFromMemory(tag, std::move(data), size, x4_loader.GetResourceCompression(tag), xfer,
selfRef);
else
ret = std::make_unique<TObjOwnerDerivedFromIObjUntyped>(nullptr);
} else {
if (auto rp = x4_loader.LoadNewResourceSync(tag, nullptr))
ret = x5c_factoryMgr.MakeObject(tag, *rp, xfer, selfRef);
else
ret = std::make_unique<TObjOwnerDerivedFromIObjUntyped>(nullptr);
}
Log.report(logvisor::Warning, fmt("sync-built {}"), tag);
return ret;
}
bool CResFactory::PumpResource(SLoadingData& data) {
if (data.x8_dvdReq && data.x8_dvdReq->IsComplete()) {
data.x8_dvdReq.reset();
*data.xc_targetPtr =
x5c_factoryMgr.MakeObjectFromMemory(data.x0_tag, std::move(data.x10_loadBuffer), data.x14_resSize,
data.m_compressed, data.x18_cvXfer, data.m_selfRef);
Log.report(logvisor::Info, fmt("async-built {}"), data.x0_tag);
return true;
}
return false;
}
std::unique_ptr<IObj> CResFactory::Build(const SObjectTag& tag, const CVParamTransfer& xfer,
CObjectReference* selfRef) {
auto search = m_loadMap.find(tag);
if (search != m_loadMap.end()) {
while (!PumpResource(*search->second) || !search->second->xc_targetPtr) {}
std::unique_ptr<IObj> ret = std::move(*search->second->xc_targetPtr);
m_loadList.erase(search->second);
m_loadMap.erase(search);
return ret;
}
return BuildSync(tag, xfer, selfRef);
}
void CResFactory::BuildAsync(const SObjectTag& tag, const CVParamTransfer& xfer, std::unique_ptr<IObj>* target,
CObjectReference* selfRef) {
auto search = m_loadMap.find(tag);
if (search == m_loadMap.end()) {
SLoadingData data(tag, target, xfer, x4_loader.GetResourceCompression(tag), selfRef);
data.x14_resSize = x4_loader.ResourceSize(tag);
if (data.x14_resSize) {
data.x10_loadBuffer = std::unique_ptr<u8[]>(new u8[data.x14_resSize]);
data.x8_dvdReq = x4_loader.LoadResourceAsync(tag, data.x10_loadBuffer.get());
AddToLoadList(std::move(data));
} else {
*target = std::make_unique<TObjOwnerDerivedFromIObjUntyped>(nullptr);
}
}
}
void CResFactory::AsyncIdle() {
if (m_loadList.empty())
return;
auto startTime = std::chrono::steady_clock::now();
while (std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::steady_clock::now() - startTime).count() <
2) {
auto& task = m_loadList.front();
if (PumpResource(task)) {
m_loadMap.erase(task.x0_tag);
m_loadList.pop_front();
if (m_loadList.empty())
return;
}
}
}
void CResFactory::CancelBuild(const SObjectTag& tag) {
auto search = m_loadMap.find(tag);
if (search != m_loadMap.end()) {
if (search->second->x8_dvdReq)
search->second->x8_dvdReq->PostCancelRequest();
m_loadList.erase(search->second);
m_loadMap.erase(search);
}
}
void CResFactory::LoadPersistentResources(CSimplePool& sp) {
const auto& paks = x4_loader.GetPaks();
for (auto it = paks.begin(); it != paks.end(); ++it) {
if (!(*it)->IsWorldPak()) {
for (const CAssetId& id : (*it)->GetDepList()) {
SObjectTag tag(GetResourceTypeById(id), id);
m_nonWorldTokens.push_back(sp.GetObj(tag));
m_nonWorldTokens.back().Lock();
}
}
}
}
} // namespace urde